├── .github └── workflows │ └── jq.yml ├── .gitignore ├── LICENSE ├── README.md ├── assets └── json │ └── engines.json ├── autoload ├── search.vim └── search │ └── util.vim ├── doc └── search.txt └── plugin └── search.vim /.github/workflows/jq.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # yamllint disable-line rule:truthy 3 | on: 4 | push: 5 | paths: 6 | - ${{ env.paths }} 7 | pull_request: 8 | paths: 9 | - ${{ env.paths }} 10 | workflow_dispatch: 11 | 12 | env: 13 | paths: assets/json/*.json 14 | 15 | jobs: 16 | test: 17 | runs-on: ubuntu-latest 18 | steps: 19 | - uses: actions/checkout@v3 20 | - name: Check if a json is sorted 21 | run: | 22 | for json in ${{ env.paths }} ; do 23 | diff <(jq -S . $json) $json || exit 1 24 | done 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # For current directory only 2 | # ---------------------------------------------------------------------------- 3 | 4 | # General 5 | # ---------------------------------------------------------------------------- 6 | *.o 7 | *.out 8 | 9 | # log 10 | *.log 11 | 12 | # cache 13 | *.cache 14 | cache/ 15 | 16 | # Windows 17 | # ---------------------------------------------------------------------------- 18 | Thumbs.db 19 | Desktop.ini 20 | 21 | # Tags 22 | # ----------------------------------------------------------------------------- 23 | TAGS 24 | !TAGS/ 25 | tags 26 | tags-cn 27 | !tags/ 28 | .tags 29 | .tags1 30 | tags.lock 31 | tags.temp 32 | gtags.files 33 | GTAGS 34 | GRTAGS 35 | GPATH 36 | cscope.files 37 | cscope.out 38 | cscope.in.out 39 | cscope.po.out 40 | 41 | # Vim 42 | # ------------------------------------------------------------------------------ 43 | [._]*.s[a-w][a-z] 44 | [._]s[a-w][a-z] 45 | *.un~ 46 | Session.vim 47 | .netrwhist 48 | *~ 49 | 50 | # Test % Tmp 51 | # ------------------------------------------------------------------------------- 52 | test.* 53 | tmp.* 54 | temp.* 55 | 56 | # Java 57 | # ------------------------------------------------------------------------------- 58 | *.class 59 | 60 | # JavaScript 61 | # ------------------------------------------------------------------------------- 62 | node_modules 63 | 64 | # Python 65 | # ------------------------------------------------------------------------------- 66 | *.pyc 67 | .idea/ 68 | /.idea 69 | build/ 70 | __pycache__ 71 | 72 | # Rust 73 | # ------------------------------------------------------------------------------- 74 | target/ 75 | **/*.rs.bk 76 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 VoldikSS 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vim-browser-search 2 | 3 | This plugin helps perform a quick web search for the text selected in (Neo)Vim 4 | 5 | ![](https://user-images.githubusercontent.com/20282795/100518567-4f189580-31cd-11eb-91f1-4d9e70f5aa0a.png) 6 | 7 | ## Installation 8 | 9 | ```vim 10 | Plug 'voldikss/vim-browser-search' 11 | ``` 12 | 13 | ## Keymappings 14 | 15 | This plugin doesn't supply any default mappings. Here are some recommended key mappings 16 | 17 | ```vim 18 | nmap s SearchNormal 19 | vmap s SearchVisual 20 | ``` 21 | 22 | ## Use cases 23 | 24 | - Select text and type `s` to do a web search 25 | 26 | - Type `saw` in to search web for a word 27 | 28 | - Type `sa(` to search web for the text wrapped in the bracket 29 | 30 | - Type `sas` to search web for a sentence 31 | 32 | - ... 33 | 34 | ## Variables 35 | 36 | #### **`g:browser_search_default_engine`** 37 | 38 | Defaut: `'google'` 39 | 40 | #### **`g:browser_search_engines`** 41 | 42 | Default: See [assets/json/engines.json](assets/json/engines.json) 43 | 44 | ## Commands 45 | 46 | #### `:BrowserSearch [text]` 47 | 48 | Search `text` with `engine`, if `text` is not given, use the word under 49 | cursor. 50 | 51 | Also, you can use this command in visual mode, i.e., `:'<,'>BrowserSearch` 52 | 53 | ## Contribution 54 | 55 | If you would like to add new engine supports, see 56 | [assets/json/engines.json](assets/json/engines.json). 57 | -------------------------------------------------------------------------------- /assets/json/engines.json: -------------------------------------------------------------------------------- 1 | { 2 | "archlinux": "https://archlinux.org/packages/?q=%s", 3 | "archlinux32": "https://archlinux32.org/packages/?q=%s", 4 | "archlinuxarm": "https://archlinuxarm.org/packages/?q=%s", 5 | "arxiv": "https://arxiv.org/search/?query=%s&searchtype=all", 6 | "aur": "https://aur.archlinux.org/packages?K=%s", 7 | "baidu": "https://www.baidu.com/s?ie=UTF-8&wd=%s", 8 | "bilibili": "https://search.bilibili.com/all?keyword=%s", 9 | "bing": "https://www.bing.com/search?q=%s", 10 | "cpan": "https://metacpan.org/search?q=%s", 11 | "csdn": "https://so.csdn.net/so/search?q=%s", 12 | "ctan": "https://ctan.org/search?phrase=%s", 13 | "cygwin": "https://cygwin.com/cgi-bin2/package-grep.cgi?grep=%s", 14 | "debain": "https://packages.debian.org/search?keywords=%s", 15 | "debian-content": "https://packages.debian.org/search?searchon=contents&keywords=%s", 16 | "dlbp": "https://dblp.org/search?q=%s", 17 | "dockerhub": "https://hub.docker.com/search?q=%s", 18 | "duckduckgo": "https://duckduckgo.com/?q=%s", 19 | "gentoo": "https://packages.gentoo.org/packages/search?q=%s", 20 | "gitee": "https://search.gitee.com/?q=%s", 21 | "github": "https://github.com/search?q=%s", 22 | "github-marketplace": "https://github.com/marketplace?query=%s", 23 | "gitlab": "https://gitlab.com/search?search=%s", 24 | "google": "https://google.com/search?q=%s", 25 | "launchpad": "https://launchpad.net/ubuntu/+search?text=%s", 26 | "luarocks": "https://luarocks.org/search?q=%s", 27 | "mdn": "https://developer.mozilla.org/en-US/search?q=%s", 28 | "msys2": "https://packages.msys2.org/search?q=%s", 29 | "nixos": "https://search.nixos.org/packages?query=%s", 30 | "npm": "https://www.npmjs.com/search?q=%s", 31 | "openembedded": "https://layers.openembedded.org/layerindex/branch/master/recipes/?q=%s", 32 | "packagecontrol": "https://packagecontrol.io/search/%s", 33 | "pypi": "https://pypi.org/search/?q=%s", 34 | "rubygems": "https://rubygems.org/search?query=%s", 35 | "salsa": "https://salsa.debian.org/search?search=%s", 36 | "savannah": "https://savannah.gnu.org/search/?type_of_search=soft&words=%s", 37 | "scholar": "https://scholar.google.com/scholar?q=%s", 38 | "stackoverflow": "https://stackoverflow.com/search?q=%s", 39 | "translate": "https://translate.google.com/?sl=auto&tl=it&text=%s", 40 | "typst": "https://typst.app/universe/search/?q=%s", 41 | "ubuntu": "https://packages.ubuntu.com/search?keywords=%s", 42 | "vimawesome": "https://vimawesome.com/?q=%s", 43 | "wikipedia": "https://en.wikipedia.org/wiki/%s", 44 | "youtube": "https://www.youtube.com/results?search_query=%s&page=&utm_source=opensearch" 45 | } 46 | -------------------------------------------------------------------------------- /autoload/search.vim: -------------------------------------------------------------------------------- 1 | " ============================================================================ 2 | " FileName: search.vim 3 | " Author: voldikss 4 | " GitHub: https://github.com/voldikss 5 | " ============================================================================ 6 | 7 | scriptencoding utf-8 8 | 9 | function! s:search(text, engine) abort 10 | let url = g:browser_search_builtin_engines[a:engine] 11 | " Replace `\n`, preserve `\` 12 | let text = substitute(a:text, '\n', ' ', 'g') 13 | let text = substitute(text, '\\', '\\\', 'g') 14 | let text = search#util#url_encode(text) 15 | 16 | " If selected text contains URL 17 | let url_in_text = matchstr(text, '\c\<\(\%([a-z][0-9A-Za-z_-]\+:\%(\/\{1,3}\|[a-z0-9%]\)\|www\d\{0,3}[.]\|[a-z0-9.\-]\+[.][a-z]\{2,4}\/\)\%([^ \t()<>]\+\|(\([^ \t()<>]\+\|\(([^ \t()<>]\+)\)\)*)\)\+\%((\([^ \t()<>]\+\|\(([^ \t()<>]\+)\)\)*)\|[^ \t`!()[\]{};:'."'".'".,<>?«»“”‘’]\)\)') 18 | if url_in_text !=# '' 19 | let url = url_in_text 20 | else 21 | let url = printf(url, text) 22 | endif 23 | 24 | " Escape double-quote, back-quote, back-slash, whitespace 25 | let url = substitute(url, '\(["`]\)','\="\\".submatch(1)','g') 26 | let url = substitute(url, '\$','\\$','g') 27 | let url = search#util#trim(url,'%20') 28 | let url = search#util#trim(url,"\\") 29 | if has('nvim') 30 | let url = shellescape(url) 31 | else 32 | let url = substitute(url, '\s', '\\ ', 'g') 33 | endif 34 | 35 | if has('win32') || has('win64') || has('win32unix') 36 | let cmd = 'rundll32 url.dll,FileProtocolHandler ' . url 37 | elseif has('mac') || has('macunix') || has('gui_macvim') || system('uname') =~? '^darwin' 38 | let cmd = 'open ' . url 39 | elseif executable('xdg-open') 40 | let cmd = 'xdg-open ' . url 41 | elseif executable('wslview') 42 | let cmd = 'wslview ' . url 43 | else 44 | call search#util#show_msg('Browser was not found', 'error') 45 | return 46 | endif 47 | 48 | if exists('*jobstart') 49 | call jobstart(cmd) 50 | elseif exists('*job_start') 51 | call job_start(cmd) 52 | else 53 | call system(cmd) 54 | endif 55 | endfunction 56 | 57 | function! search#search_normal(visual_type) abort 58 | let reg_tmp = @" 59 | if index(['v', 'V'], a:visual_type) >=0 60 | normal! `y 61 | elseif index(['char', 'line'], a:visual_type) >= 0 62 | normal! `[v`]y 63 | else 64 | return 65 | endif 66 | let text = @" 67 | let @" = reg_tmp 68 | call s:search(text, get(b:, 'browser_search_default_engine', g:browser_search_default_engine)) 69 | call setpos('.', g:browser_search_curpos) 70 | endfunction 71 | 72 | function! search#search_visual() abort 73 | let reg_tmp = @" 74 | normal! gv""y 75 | let text=@" 76 | let @" = reg_tmp 77 | call s:search(text, get(b:, 'browser_search_default_engine', g:browser_search_default_engine)) 78 | endfunction 79 | 80 | let s:has_popup = has('textprop') && has('patch-8.2.0286') 81 | let s:has_float = has('nvim') && exists('*nvim_win_set_config') 82 | let s:text = '' 83 | let s:enginelist = [] 84 | function! search#start(text, visualmode, range) abort 85 | if empty(a:text) 86 | if a:visualmode == 'v' && a:range == 2 87 | let s:text = search#util#get_selected_text() 88 | else 89 | let s:text = expand('') 90 | endif 91 | else 92 | let s:text = a:text 93 | endif 94 | if empty(search#util#trim(s:text, ' ')) | return | endif 95 | 96 | let s:enginelist = keys(g:browser_search_builtin_engines) 97 | let engine_index = index(s:enginelist, g:browser_search_default_engine) 98 | 99 | if s:has_popup 100 | function! s:bs_menu_filter(id, key) 101 | return popup_filter_menu(a:id, a:key) 102 | endfunction 103 | 104 | function! s:bs_menu_handler(id, index) abort 105 | if a:index == -1 | return | endif 106 | let engine = s:enginelist[a:index-1] 107 | call s:search(s:text, engine) 108 | endfunction 109 | 110 | call popup_menu(s:enginelist, { 111 | \ 'filter': function('s:bs_menu_filter'), 112 | \ 'callback': function('s:bs_menu_handler'), 113 | \ 'minheight': len(s:enginelist), 114 | \ 'minwidth': max(map(deepcopy(s:enginelist), {_, val -> len(val)})), 115 | \ 'title': 'Browser Search Engines', 116 | \ 'drap': v:true, 117 | \ 'resize': v:true, 118 | \ 'scrollbar': 1, 119 | \ }) 120 | return 121 | endif 122 | 123 | if s:has_float 124 | let s:saved_cursor = &guicursor 125 | let bufnr = nvim_create_buf(v:false, v:true) 126 | let candidates = map(deepcopy(s:enginelist), { engine_index, val -> engine_index+1.'. '.val }) 127 | call nvim_buf_set_lines(bufnr, 0, -1, v:true, candidates) 128 | call nvim_buf_set_option(bufnr, 'modifiable', v:false) 129 | 130 | let options = { 131 | \ 'width': max(map(deepcopy(s:enginelist), {_, val -> len(val)})) + 2, 132 | \ 'height': len(s:enginelist), 133 | \ 'relative': 'cursor', 134 | \ 'row': 0, 135 | \ 'col': 0, 136 | \ 'style': 'minimal', 137 | \} 138 | let s:winid = nvim_open_win(bufnr, v:true, options) 139 | call nvim_win_set_option(s:winid, 'foldcolumn', '1') 140 | call nvim_win_set_option(s:winid, 'cursorline', v:true) 141 | call nvim_win_set_option(s:winid, 'winhl', 'Normal:Pmenu,FoldColumn:Pmenu,CursorLine:PmenuSel') 142 | call nvim_win_set_cursor(s:winid, [engine_index+1, 0]) 143 | 144 | if has('nvim-0.5.0') && !empty(s:saved_cursor) 145 | set guicursor+=a:ver1-Cursor/lCursor 146 | endif 147 | 148 | function! s:select_and_search() abort 149 | let engine = s:enginelist[line('.') - 1] 150 | call s:search(s:text, engine) 151 | call s:close_menu() 152 | endfunction 153 | 154 | function! s:close_menu() abort 155 | call nvim_win_close(s:winid, v:true) 156 | if has('nvim-0.5.0') && !empty(s:saved_cursor) 157 | let &guicursor = s:saved_cursor 158 | endif 159 | endfunction 160 | 161 | mapclear 162 | nnoremap :call select_and_search() 163 | nnoremap l :call select_and_search() 164 | nnoremap :call close_menu() 165 | for idx in range(len(s:enginelist)) 166 | execute printf('nmap %s :%s', idx + 1, idx) 167 | endfor 168 | return 169 | endif 170 | 171 | let candidates = map(deepcopy(s:enginelist), { engine_index, val -> engine_index+1.'. '.val }) 172 | let select = inputlist(candidates) - 1 173 | if select < 1 || select > len(candidates) 174 | return 175 | endif 176 | let engine = s:enginelist[select] 177 | call s:search(s:text, engine) 178 | endfunction 179 | -------------------------------------------------------------------------------- /autoload/search/util.vim: -------------------------------------------------------------------------------- 1 | " ============================================================================ 2 | " FileName: util.vim 3 | " Author: voldikss 4 | " GitHub: https://github.com/voldikss 5 | " ============================================================================ 6 | 7 | function! s:Echo(group, msg) abort 8 | if a:msg ==# '' | return | endif 9 | execute 'echohl' a:group 10 | echo a:msg 11 | echon ' ' 12 | echohl NONE 13 | endfunction 14 | 15 | function! s:Echon(group, msg) abort 16 | if a:msg ==# '' | return | endif 17 | execute 'echohl' a:group 18 | echon a:msg 19 | echon ' ' 20 | echohl NONE 21 | endfunction 22 | 23 | function! search#util#show_msg(message, ...) abort 24 | if a:0 == 0 25 | let msg_type = 'info' 26 | else 27 | let msg_type = a:1 28 | endif 29 | 30 | if type(a:message) != 1 31 | let message = string(a:message) 32 | else 33 | let message = a:message 34 | endif 35 | 36 | call s:Echo('Constant', '[vim-browser-search]') 37 | 38 | if msg_type ==# 'info' 39 | call s:Echon('Normal', message) 40 | elseif msg_type ==# 'warning' 41 | call s:Echon('WarningMsg', message) 42 | elseif msg_type ==# 'error' 43 | call s:Echon('Error', message) 44 | endif 45 | endfunction 46 | 47 | function! search#util#trim(input, mask) abort 48 | let input = substitute(a:input, a:mask . '$', '', '') 49 | let input = substitute(input, '^' . a:mask, '', '') 50 | return input 51 | endfunction 52 | 53 | function! search#util#get_selected_text() abort 54 | let col1 = getpos("'<")[2] 55 | let col2 = getpos("'>")[2] 56 | let text = getline('.') 57 | if empty(text) 58 | call skylight#util#show_msg('No content', 'error') 59 | return '' 60 | endif 61 | let text = text[col1-1 : col2-1] 62 | return text 63 | endfunction 64 | 65 | " https://vi.stackexchange.com/questions/42717/how-do-i-turn-a-string-into-url-encoded-string 66 | " URL encode a string. ie. Percent-encode characters as necessary. 67 | function! search#util#url_encode(string) 68 | 69 | let result = "" 70 | 71 | let characters = split(a:string, '.\zs') 72 | for character in characters 73 | if character == " " 74 | let result = result . "+" 75 | elseif CharacterRequiresUrlEncoding(character) 76 | let i = 0 77 | while i < strlen(character) 78 | let byte = strpart(character, i, 1) 79 | let decimal = char2nr(byte) 80 | let result = result . "%" . printf("%02x", decimal) 81 | let i += 1 82 | endwhile 83 | else 84 | let result = result . character 85 | endif 86 | endfor 87 | 88 | return result 89 | 90 | endfunction 91 | 92 | " Returns 1 if the given character should be percent-encoded in a URL encoded 93 | " string. 94 | function! CharacterRequiresUrlEncoding(character) 95 | 96 | let ascii_code = char2nr(a:character) 97 | if ascii_code >= 48 && ascii_code <= 57 98 | return 0 99 | elseif ascii_code >= 65 && ascii_code <= 90 100 | return 0 101 | elseif ascii_code >= 97 && ascii_code <= 122 102 | return 0 103 | elseif a:character == "-" || a:character == "_" || a:character == "." || a:character == "~" 104 | return 0 105 | endif 106 | 107 | return 1 108 | 109 | endfunction 110 | -------------------------------------------------------------------------------- /doc/search.txt: -------------------------------------------------------------------------------- 1 | *vim-browser-search.txt* Plugin for web search Last change: 2019-12-28 2 | 3 | Author: voldikss 4 | License: MIT 5 | 6 | CONTENTS *browser-search-contents* 7 | 8 | Introduction |browser-search-introduction| 9 | Installation |browser-search-installation| 10 | Keymappings |browser-search-key-mappings| 11 | Usecases |browser-search-usecases| 12 | Variables |browser-search-variables| 13 | Commands |browser-search-command| 14 | About |browser-search-about| 15 | Repository |browser-search-repository| 16 | 17 | ============================================================================== 18 | INTRODUCTION *browser-search-introduction* 19 | 20 | This plugin helps perform a quick web search for the text selected in (Neo)Vim 21 | 22 | 23 | ============================================================================== 24 | INSTALLATION *browser-search-installation* 25 | 26 | With vim-plug 27 | > 28 | Plug 'voldikss/vim-browser-search' 29 | 30 | 31 | ============================================================================== 32 | KEYMAP *browser-search-keymap* 33 | 34 | This plugin doesn't supply default mappings. Here are some recommended 35 | key mappings 36 | > 37 | nmap s SearchNormal 38 | vmap s SearchVisual 39 | < 40 | 41 | ============================================================================== 42 | USECASES *browser-search-usecases* 43 | 44 | Select text and type `s` to do a web search 45 | 46 | Type `saw` in to search web for a word 47 | 48 | Type `sa(` to search web for the text wrapped in the bracket 49 | 50 | Type `sas` to search web for a sentence 51 | 52 | ... 53 | 54 | 55 | ============================================================================== 56 | VARIABLES *browser-search-variables* 57 | 58 | g:browser_search_default_engine *g:browser_search_default_engine* 59 | 60 | Defaut: `'google'` 61 | 62 | g:browser_search_engines *g:browser_search_engines* 63 | 64 | Defaut: 65 | > 66 | { 67 | \ 'google':'https://google.com/search?q=%s', 68 | \ 'github':'https://github.com/search?q=%s', 69 | \ 'stackoverflow':'https://stackoverflow.com/search?q=%s', 70 | \ 'bing': 'https://www.bing.com/search?q=%s', 71 | \ 'duckduckgo': 'https://duckduckgo.com/?q=%s', 72 | \ 'wikipedia': 'https://en.wikipedia.org/wiki/%s', 73 | \ 'youtube':'https://www.youtube.com/results?search_query=%s&page=&utm_source=opensearch', 74 | \ 'baidu':'https://www.baidu.com/s?ie=UTF-8&wd=%s' 75 | \ } 76 | < 77 | 78 | ============================================================================== 79 | COMMANDS *browser-search-commands* 80 | 81 | :BrowserSearch [text] *BrowserSearch* 82 | 83 | Search `text` with `engine`, if `text` is not given, use the word under 84 | cursor. 85 | 86 | Also, you can use this command in visual mode, i.e., `:'<,'>BrowserSearch` 87 | 88 | 89 | ============================================================================== 90 | REPOSITORY *browser-search-repository* 91 | 92 | |vim-browser-search| is developed on GitHub. 93 | 94 | https://github.com/voldikss/vim-browser-search 95 | 96 | 97 | ============================================================================== 98 | vim:tw=78:nosta:noet:ts=8:sts=0:ft=help:noet:fen:fdm=marker: 99 | -------------------------------------------------------------------------------- /plugin/search.vim: -------------------------------------------------------------------------------- 1 | " ============================================================================ 2 | " FileName: search.vim 3 | " Description: 4 | " Author: voldikss 5 | " GitHub: https://github.com/voldikss 6 | " ============================================================================ 7 | 8 | if exists('g:did_load_browser_search') 9 | finish 10 | endif 11 | let g:did_load_browser_search = 1 12 | 13 | let s:path = fnamemodify(resolve(expand(':p')), ':h:h') 14 | let s:json_path = s:path . '/assets/json/engines.json' 15 | 16 | let g:browser_search_default_engine = get(g:, 'browser_search_default_engine', 'google') 17 | let g:browser_search_builtin_engines = json_decode(join(readfile(s:json_path), '')) 18 | if exists('g:browser_search_engines') 19 | call extend(g:browser_search_builtin_engines, g:browser_search_engines) 20 | endif 21 | 22 | nnoremap SearchNormal :let g:browser_search_curpos = getpos('.') \| set operatorfunc=search#search_normalg@ 23 | vnoremap SearchVisual :call search#search_visual() 24 | 25 | command! -nargs=* -range BrowserSearch call search#start(, visualmode(), ) 26 | --------------------------------------------------------------------------------