Advertisement
FocusedWolf

Vim: Search

Aug 8th, 2017
781
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
VIM 35.00 KB | None | 0 0
  1. " Online post: https://stackoverflow.com/a/45579817/490748
  2.  
  3. """""""""""
  4. " A sexy commandline-based search menu can be accessed by <Shift-F>, which makes remembering the functions below pointless.
  5. "
  6. " Various functions for searching are implemented below:
  7. "     :GrepBuffer [pattern] [matchCase] [matchWholeWord] [prefix]
  8. "     :GrepTab [pattern] [matchCase] [matchWholeWord] [prefix]
  9. "     :GrepTabs [pattern] [matchCase] [matchWholeWord] [prefix]
  10. "     :GrepBuffers [pattern] [matchCase] [matchWholeWord] [prefix]
  11. "     :GrepFiles [pattern] [matchCase] [matchWholeWord] [prefix]
  12. "
  13. " Shorthand versions that use the word that the caret is on as the pattern, or if you have a visual selection then it will use that, and if the caret is not on a word, and their is no visual selection, then you get another sexy menu to type in what you want to search:
  14. "     :SearchBuffer [matchCase] [matchWholeWord] [prefix]
  15. "     :SearchTab [matchCase] [matchWholeWord] [prefix]
  16. "     :SearchTabs [matchCase] [matchWholeWord] [prefix]
  17. "     :SearchBuffers [matchCase] [matchWholeWord] [prefix]
  18. "     :SearchFiles [matchCase] [matchWholeWord] [prefix]
  19. "
  20. " Note: matchCase = [0,1]
  21. " Note: matchWholeWord = [0,1]
  22. " Note: prefix = 'c' for QuickFix list or 'l' for location list for the current window
  23. "
  24. " USAGE: When you see a QuickFix with search results, you will find that the arrow keys will have been mapped to allow navigation of the QuickFix list with easy.
  25. "        When you are done searching, press <F3> to close the QuickFix window and this will restore the default arrow key behavior.
  26. """""""""""
  27.  
  28.  
  29.  
  30. " This setting controls the behavior when switching buffers
  31. " useopen ensures that a new window will not be created if an existing window already contains the specified buffer.
  32. " usetab ensure that a new tab will not be created if an existing tab already contains the specified buffer.
  33. " split will open a new vertically-stacked window to display the buffers that are not displayed elsewhere.
  34. " vsplit will open a new horizontally-stacked window to display the buffers that are not displayed elsewhere.
  35. " newtab will open a new tab to display the buffers that are not displayed elsewhere.
  36.  
  37. " NOTE: QuickFix commands are affected by this setting
  38. set switchbuf=useopen,usetab,newtab
  39.  
  40.  
  41.  
  42. " Bind F3 to clear QuickFix windows, location list for the current windows, search highlights, and restore <left> <right> <up> <down> binds {{{
  43.  
  44. function! TabCleanup()
  45.     cclose
  46.     lclose
  47. endfunction
  48.  
  49. function! MoreCleanup()
  50.     call s:RestoreArrowKeyBinds()
  51.     call setqflist([])
  52.     redraw!
  53. endfunction
  54.  
  55. nnoremap <F3> :tabdo :call TabCleanup()<CR><BAR>:call MoreCleanup()<CR><BAR>:nohlsearch<CR><BAR>:echo ''<CR>
  56.  
  57. " }}} Bind F3 to clear quickfix window, location list for the current window, and search highlights
  58.  
  59.  
  60.  
  61. " Bind Shift + F to display search menu {{{
  62.  
  63. function! DisplaySearchMenu()
  64.     let guicursor = &guicursor
  65.     let &guicursor = 'a:hl-None' "hide the blinking cursor
  66.     try
  67.         let l:enterChar = 13
  68.         let l:escapeChar = 27
  69.         let l:leftChar = "\<Left>"
  70.         let l:rightChar = "\<Right>"
  71.  
  72.         let l:searchText = ''
  73.         let l:searchLocation = 'W'
  74.         let l:searchOptionMatchCase = 0
  75.         let l:searchOptionMatchWholeWord = 0
  76.  
  77.         let l:STAGE_DONE = 0
  78.         let l:STAGE_GET_SEARCH_TEXT = 1
  79.         let l:STAGE_GET_SEARCH_LOCATION = 2
  80.         let l:STAGE_GET_SEARCH_OPTIONS = 3
  81.  
  82.         let l:stage = l:STAGE_GET_SEARCH_TEXT
  83.         while l:stage != l:STAGE_DONE
  84.             if l:stage == l:STAGE_GET_SEARCH_TEXT
  85.                 while 1
  86.                     let l:searchText = s:GetSearchText(l:searchText)
  87.                     if l:searchText != ''
  88.                         let l:stage = l:STAGE_GET_SEARCH_LOCATION
  89.                         break
  90.                     endif
  91.                 endwhile
  92.             elseif l:stage == l:STAGE_GET_SEARCH_LOCATION
  93.                 while 1
  94.                     echohl Question | echon "Search Target: "
  95.                     echohl Title | echon l:searchText
  96.                     echohl Question | echon " Search Location: "
  97.  
  98.                     if l:searchLocation == 'W'
  99.                         echohl WarningMsg | echon "[W]indow "
  100.                     else
  101.                         echohl SpecialKey | echon "[W]" | echohl Question | echon "indow "
  102.                     endif
  103.  
  104.                     if l:searchLocation == 'V'
  105.                         echohl WarningMsg | echon "[V]isible "
  106.                     else
  107.                         echohl SpecialKey | echon "[V]" | echohl Question | echon "isible "
  108.                     endif
  109.  
  110.                     if l:searchLocation == 'T'
  111.                         echohl WarningMsg | echon "[T]abs "
  112.                     else
  113.                         echohl SpecialKey | echon "[T]" | echohl Question | echon "abs "
  114.                     endif
  115.  
  116.                     if l:searchLocation == 'B'
  117.                         echohl WarningMsg | echon "[B]uffers "
  118.                     else
  119.                         echohl SpecialKey | echon "[B]" | echohl Question | echon "uffers "
  120.                     endif
  121.  
  122.                     if l:searchLocation == 'F'
  123.                         echohl WarningMsg | echon "[F]iles "
  124.                     else
  125.                         echohl SpecialKey | echon "[F]" | echohl Question | echon "iles "
  126.                     endif
  127.                     echohl Normal
  128.  
  129.                     let l:key = getchar()
  130.                     let l:char = toupper(nr2char(l:key))
  131.  
  132.                     redraw!
  133.                     "echon "\r\r"
  134.                     "echon ''
  135.  
  136.                     let l:choice_map = {}
  137.                     let l:choice_map['W'] = 's:GrepBuffer'
  138.                     let l:choice_map['V'] = 's:GrepTab'
  139.                     let l:choice_map['T'] = 's:GrepTabs'
  140.                     let l:choice_map['B'] = 's:GrepBuffers'
  141.                     let l:choice_map['F'] = 's:GrepFiles'
  142.  
  143.                     if l:key == l:escapeChar
  144.                         let l:stage = l:STAGE_GET_SEARCH_TEXT
  145.                         break
  146.                     elseif l:key == l:enterChar
  147.                         let l:stage = l:STAGE_GET_SEARCH_OPTIONS
  148.                         break
  149.                     elseif l:key == l:leftChar
  150.                         if l:searchLocation == 'W'
  151.                             let l:searchLocation = 'F'
  152.                         elseif l:searchLocation == 'V'
  153.                             let l:searchLocation = 'W'
  154.                         elseif l:searchLocation == 'T'
  155.                             let l:searchLocation = 'V'
  156.                         elseif l:searchLocation == 'B'
  157.                             let l:searchLocation = 'T'
  158.                         elseif l:searchLocation == 'F'
  159.                             let l:searchLocation = 'B'
  160.                         endif
  161.                     elseif l:key == l:rightChar
  162.                         if l:searchLocation == 'W'
  163.                             let l:searchLocation = 'V'
  164.                         elseif l:searchLocation == 'V'
  165.                             let l:searchLocation = 'T'
  166.                         elseif l:searchLocation == 'T'
  167.                             let l:searchLocation = 'B'
  168.                         elseif l:searchLocation == 'B'
  169.                             let l:searchLocation = 'F'
  170.                         elseif l:searchLocation == 'F'
  171.                             let l:searchLocation = 'W'
  172.                         endif
  173.                     elseif has_key(l:choice_map, l:char)
  174.                         let l:searchLocation = l:char
  175.                     endif
  176.                 endwhile
  177.                 let l:searchFunction = l:choice_map[l:searchLocation]
  178.             elseif l:stage == l:STAGE_GET_SEARCH_OPTIONS
  179.                 while 1
  180.                     echohl Question | echon "Search Target: " | echohl Title | echon l:searchText
  181.                     echohl Question | echon " Search Location: "
  182.  
  183.                     if l:searchLocation == 'W'
  184.                         echohl Title | echon 'WINDOW'
  185.                     elseif l:searchLocation == 'V'
  186.                         echohl Title | echon 'VISIBLE'
  187.                     elseif l:searchLocation == 'T'
  188.                         echohl Title | echon 'TABS'
  189.                     elseif l:searchLocation == 'B'
  190.                         echohl Title | echon 'BUFFERS'
  191.                     elseif l:searchLocation == 'F'
  192.                         echohl Title | echon 'FILES'
  193.                     endif
  194.  
  195.                     echohl Question | echon ' Search Options: '
  196.  
  197.                     if l:searchOptionMatchCase == 0
  198.                         echohl SpecialKey | echon "[C]" | echohl Question | echon "ase "
  199.                     else
  200.                         echohl WarningMsg | echon "[C]ase "
  201.                     endif
  202.  
  203.                     if l:searchOptionMatchWholeWord == 0
  204.                         echohl SpecialKey | echon "[W]" | echohl Question | echon "hole "
  205.                     else
  206.                         echohl WarningMsg | echon "[W]hole "
  207.                     endif
  208.  
  209.                     echohl Normal
  210.  
  211.                     let l:key = getchar()
  212.                     let l:char = toupper(nr2char(l:key))
  213.  
  214.                     redraw!
  215.                     "echon "\r\r"
  216.                     "echon ''
  217.  
  218.                     let l:choice_map = {}
  219.                     let l:choice_map['C'] = 'let l:searchOptionMatchCase = !l:searchOptionMatchCase'
  220.                     let l:choice_map['W'] = 'let l:searchOptionMatchWholeWord = !l:searchOptionMatchWholeWord'
  221.  
  222.                     if l:key == l:escapeChar
  223.                         let l:stage = l:STAGE_GET_SEARCH_LOCATION
  224.                         break
  225.                     elseif l:key == l:enterChar
  226.                         execute 'call ' . l:searchFunction . '("' . l:searchText . '", ' . l:searchOptionMatchCase . ', ' . l:searchOptionMatchWholeWord . ')'
  227.                         let l:stage = l:STAGE_DONE
  228.                         break
  229.                     elseif l:key == l:leftChar
  230.                         if !l:searchOptionMatchCase && !l:searchOptionMatchWholeWord
  231.                             let l:searchOptionMatchCase = 0
  232.                             let l:searchOptionMatchWholeWord = 1
  233.                         elseif l:searchOptionMatchCase && !l:searchOptionMatchWholeWord
  234.                             let l:searchOptionMatchCase = 0
  235.                             let l:searchOptionMatchWholeWord = 0
  236.                         elseif l:searchOptionMatchCase && l:searchOptionMatchWholeWord
  237.                             let l:searchOptionMatchCase = 1
  238.                             let l:searchOptionMatchWholeWord = 0
  239.                         elseif !l:searchOptionMatchCase && l:searchOptionMatchWholeWord
  240.                             let l:searchOptionMatchCase = 1
  241.                             let l:searchOptionMatchWholeWord = 1
  242.                         endif
  243.                     elseif l:key == l:rightChar
  244.                         if !l:searchOptionMatchCase && !l:searchOptionMatchWholeWord
  245.                             let l:searchOptionMatchCase = 1
  246.                             let l:searchOptionMatchWholeWord = 0
  247.                         elseif l:searchOptionMatchCase && !l:searchOptionMatchWholeWord
  248.                             let l:searchOptionMatchCase = 1
  249.                             let l:searchOptionMatchWholeWord = 1
  250.                         elseif l:searchOptionMatchCase && l:searchOptionMatchWholeWord
  251.                             let l:searchOptionMatchCase = 0
  252.                             let l:searchOptionMatchWholeWord = 1
  253.                         elseif !l:searchOptionMatchCase && l:searchOptionMatchWholeWord
  254.                             let l:searchOptionMatchCase = 0
  255.                             let l:searchOptionMatchWholeWord = 0
  256.                         endif
  257.                     elseif has_key(l:choice_map, l:char)
  258.                         execute(l:choice_map[l:char])
  259.                     endif
  260.                 endwhile
  261.             endif
  262.         endwhile
  263.     catch /user\ cancelled\ providing\ input/
  264.     finally
  265.         let &guicursor = guicursor
  266.     endtry
  267. endfunction
  268.  
  269. nnoremap <S-F> :call DisplaySearchMenu()<CR>
  270. " NOTE: <C-u> removes the '<,'> visual-selection from the command line. See :h c_CTRL-u
  271. vnoremap <S-F> :<C-u>call DisplaySearchMenu()<CR>
  272.  
  273. " }}} Bind Shift + F to display search options
  274. " Search windows, tabs, and files {{{
  275.  
  276. " SOURCE: https://stackoverflow.com/questions/11975174/how-do-i-search-the-open-buffers-in-vim/11978447#11978447
  277.  
  278. " This option controls the behavior when switching buffers
  279. " useopen, and usetab ensure that a new window|tab will not be created if an existing window|tab already contains the specified buffer.
  280. " newtab will open a new tab to display the buffers that are not open in any other window|tab.
  281. " NOTE: QuickFix commands are affected by this option
  282. " set switchbuf=useopen,usetab,newtab
  283.  
  284. " Clear QuickFix window with :cclose
  285. " Clear location list for the current window with :lclose
  286. " NOTE: These are binded to F3 now, which also clears search highlights.
  287.  
  288. " Looks for a pattern in the current buffer.
  289. " Usage :GrepBuffer [pattern] [matchCase] [matchWholeWord] [prefix]
  290. " If pattern is not specified then usage instructions will get printed.
  291. " If matchCase = '1' then exclude matches that do not have the same case. If matchCase = '0' then ignore case.
  292. " If prefix == 'c' then put results in the QuickFix list. If prefix == 'l' then put results in the location list for the current window.
  293. function! s:GrepBuffer(...)
  294.     if a:0 > 4
  295.         throw "Too many arguments"
  296.     endif
  297.  
  298.     if a:0 >= 1
  299.         let l:pattern = a:1
  300.     else
  301.         echo 'Usage :GrepBuffer [pattern] [matchCase] [matchWholeWord] [prefix]'
  302.         return
  303.     endif
  304.  
  305.     let l:matchCase = 0
  306.     if a:0 >= 2
  307.         if a:2 !~ '^\d\+$' || a:2 > 1 || a:2 < 0
  308.             throw "ArgumentException: matchCase value '" . a:2 . "' is not in the bounds [0,1]."
  309.         endif
  310.         let l:matchCase = a:2
  311.     endif
  312.  
  313.     let l:matchWholeWord = 0
  314.     if a:0 >= 3
  315.         if a:3 !~ '^\d\+$' || a:3 > 1 || a:3 < 0
  316.             throw "ArgumentException: matchWholeWord value '" . a:3 . "' is not in the bounds [0,1]."
  317.         endif
  318.         let l:matchWholeWord = a:3
  319.     endif
  320.  
  321.     let l:prefix = 'c'
  322.     if a:0 >= 4
  323.         if a:4 != 'c' && a:4 != 'l'
  324.             throw "ArgumentException: prefix value '" . a:4 . "' is not 'c' or 'l'."
  325.         endif
  326.         let l:prefix = a:4
  327.     endif
  328.  
  329.     let ignorecase = &ignorecase
  330.     let &ignorecase = l:matchCase == 0
  331.     try
  332.         call s:BindArrowKeysToQuickFixNavigation()
  333.  
  334.         let str = ''
  335.  
  336.         if l:prefix == 'l'
  337.             let str = 'l'
  338.         endif
  339.  
  340.         if l:matchWholeWord
  341.             let str = str . 'silent vimgrep /\<' . l:pattern . '\>/'
  342.         else
  343.             let str = str . 'silent vimgrep /' . l:pattern . '/'
  344.         endif
  345.  
  346.         let currentBufnr = bufnr('%')
  347.  
  348.         if buflisted(currentBufnr) " Skips unlisted buffers because they are not used for normal editing
  349.             if !bufexists(currentBufnr)
  350.                 throw 'Buffer does not exist: "' . currentBufnr . '"'
  351.             elseif empty(bufname(currentBufnr)) && getbufvar(currentBufnr, '&buftype') != 'quickfix'
  352.                 if len(getbufline(currentBufnr, '2')) != 0 || strlen(getbufline(currentBufnr, '1')[0]) != 0
  353.                     echohl warningmsg | echomsg 'Skipping unnamed buffer: [' . currentBufnr . ']' | echohl normal
  354.                 endif
  355.             else
  356.                 let str = str . ' ' . fnameescape(bufname(currentBufnr))
  357.             endif
  358.         endif
  359.  
  360.         try
  361.             execute str
  362.         catch /^Vim\%((\a\+)\)\=:E\%(683\|480\):/ "E683: File name missing or invalid pattern --- E480: No match:
  363.             call s:RestoreArrowKeyBinds()
  364.             echomsg v:exception
  365.         endtry
  366.  
  367.         execute l:prefix . 'window'
  368.     finally
  369.         let &ignorecase = ignorecase
  370.     endtry
  371. endfunction
  372.  
  373. " Usage :GrepBuffer [pattern] [matchCase] [matchWholeWord] [prefix]
  374. command! -nargs=* GrepBuffer call s:GrepBuffer(<f-args>)
  375.  
  376. " Usage :SearchBuffer [matchCase] [matchWholeWord] [prefix]
  377. " Use the word under the cursor as the pattern.
  378. command! -nargs=* SearchBuffer call s:CatchCancel('call s:GrepBuffer(s:GetSearchText(), <f-args>)')
  379.  
  380. " Looks for a pattern in the open windows of the current tab.
  381. " Usage :GrepTab [pattern] [matchCase] [matchWholeWord] [prefix]
  382. " If pattern is not specified then usage instructions will get printed.
  383. " If matchCase = '1' then exclude matches that do not have the same case. If matchCase = '0' then ignore case.
  384. " If prefix == 'c' then put results in the QuickFix list. If prefix == 'l' then put results in the location list for the current window.
  385. function! s:GrepTab(...)
  386.     if a:0 > 4
  387.         throw "Too many arguments"
  388.     endif
  389.  
  390.     if a:0 >= 1
  391.         let l:pattern = a:1
  392.     else
  393.         echo 'Usage :GrepTab [pattern] [matchCase] [matchWholeWord] [prefix]'
  394.         return
  395.     endif
  396.  
  397.     let l:matchCase = 0
  398.     if a:0 >= 2
  399.         if a:2 !~ '^\d\+$' || a:2 > 1 || a:2 < 0
  400.             throw "ArgumentException: matchCase value '" . a:2 . "' is not in the bounds [0,1]."
  401.         endif
  402.         let l:matchCase = a:2
  403.     endif
  404.  
  405.     let l:matchWholeWord = 0
  406.     if a:0 >= 3
  407.         if a:3 !~ '^\d\+$' || a:3 > 1 || a:3 < 0
  408.             throw "ArgumentException: matchWholeWord value '" . a:3 . "' is not in the bounds [0,1]."
  409.         endif
  410.         let l:matchWholeWord = a:3
  411.     endif
  412.  
  413.     let l:prefix = 'c'
  414.     if a:0 >= 4
  415.         if a:4 != 'c' && a:4 != 'l'
  416.             throw "ArgumentException: prefix value '" . a:4 . "' is not 'c' or 'l'."
  417.         endif
  418.         let l:prefix = a:4
  419.     endif
  420.  
  421.     let ignorecase = &ignorecase
  422.     let &ignorecase = l:matchCase == 0
  423.     try
  424.         call s:BindArrowKeysToQuickFixNavigation()
  425.  
  426.         let str = ''
  427.  
  428.         if l:prefix == 'l'
  429.             let str = 'l'
  430.         endif
  431.  
  432.         if l:matchWholeWord
  433.             let str = str . 'silent vimgrep /\<' . l:pattern . '\>/'
  434.         else
  435.             let str = str . 'silent vimgrep /' . l:pattern . '/'
  436.         endif
  437.  
  438.         let currentTabnr = tabpagenr()
  439.  
  440.         for bufnr in tabpagebuflist(currentTabnr)
  441.             if buflisted(bufnr) " Skips unlisted buffers because they are not used for normal editing
  442.                 if !bufexists(bufnr)
  443.                     throw 'Buffer does not exist: "' . bufnr . '"'
  444.                 elseif empty(bufname(bufnr)) && getbufvar(bufnr, '&buftype') != 'quickfix'
  445.                     if len(getbufline(bufnr, '2')) != 0 || strlen(getbufline(bufnr, '1')[0]) != 0
  446.                         echohl warningmsg | echomsg 'Skipping unnamed buffer: [' . bufnr . ']' | echohl normal
  447.                     endif
  448.                 else
  449.                     let str = str . ' ' . fnameescape(bufname(bufnr))
  450.                 endif
  451.             endif
  452.         endfor
  453.  
  454.         try
  455.             execute str
  456.         catch /^Vim\%((\a\+)\)\=:E\%(683\|480\):/ "E683: File name missing or invalid pattern --- E480: No match:
  457.             call s:RestoreArrowKeyBinds()
  458.             echomsg v:exception
  459.         endtry
  460.  
  461.         execute l:prefix . 'window'
  462.     finally
  463.         let &ignorecase = ignorecase
  464.     endtry
  465. endfunction
  466.  
  467. " Usage :GrepTab [pattern] [matchCase] [matchWholeWord] [prefix]
  468. command! -nargs=* GrepTab call s:GrepTab(<f-args>)
  469.  
  470. " Usage :SearchTab [matchCase] [matchWholeWord] [prefix]
  471. " Use the word under the cursor as the pattern.
  472. command! -nargs=* SearchTab call s:CatchCancel('call s:GrepTab(s:GetSearchText(), <f-args>)')
  473.  
  474. " Looks for a pattern in the open windows of every tab.
  475. " Usage :GrepTabs [pattern] [matchCase] [matchWholeWord] [prefix]
  476. " If pattern is not specified then usage instructions will get printed.
  477. " If matchCase = '1' then exclude matches that do not have the same case. If matchCase = '0' then ignore case.
  478. " If prefix == 'c' then put results in the QuickFix list. If prefix == 'l' then put results in the location list for the current window.
  479. function! s:GrepTabs(...)
  480.     if a:0 > 4
  481.         throw "Too many arguments"
  482.     endif
  483.  
  484.     if a:0 >= 1
  485.         let l:pattern = a:1
  486.     else
  487.         echo 'Usage :GrepTabs [pattern] [matchCase] [matchWholeWord] [prefix]'
  488.         return
  489.     endif
  490.  
  491.     let l:matchCase = 0
  492.     if a:0 >= 2
  493.         if a:2 !~ '^\d\+$' || a:2 > 1 || a:2 < 0
  494.             throw "ArgumentException: matchCase value '" . a:2 . "' is not in the bounds [0,1]."
  495.         endif
  496.         let l:matchCase = a:2
  497.     endif
  498.  
  499.     let l:matchWholeWord = 0
  500.     if a:0 >= 3
  501.         if a:3 !~ '^\d\+$' || a:3 > 1 || a:3 < 0
  502.             throw "ArgumentException: matchWholeWord value '" . a:3 . "' is not in the bounds [0,1]."
  503.         endif
  504.         let l:matchWholeWord = a:3
  505.     endif
  506.  
  507.     let l:prefix = 'c'
  508.     if a:0 >= 4
  509.         if a:4 != 'c' && a:4 != 'l'
  510.             throw "ArgumentException: prefix value '" . a:4 . "' is not 'c' or 'l'."
  511.         endif
  512.         let l:prefix = a:4
  513.     endif
  514.  
  515.     let ignorecase = &ignorecase
  516.     let &ignorecase = l:matchCase == 0
  517.     try
  518.         call s:BindArrowKeysToQuickFixNavigation()
  519.  
  520.         let str = ''
  521.  
  522.         if l:prefix == 'l'
  523.             let str = 'l'
  524.         endif
  525.  
  526.         if l:matchWholeWord
  527.             let str = str . 'silent vimgrep /\<' . l:pattern . '\>/'
  528.         else
  529.             let str = str . 'silent vimgrep /' . l:pattern . '/'
  530.         endif
  531.  
  532.         for buf in getbufinfo()
  533.             if buflisted(buf.bufnr) " Skips unlisted buffers because they are not used for normal editing
  534.                 if !empty(buf.windows) " Skip buffers that have no associated windows
  535.                     if !bufexists(buf.bufnr)
  536.                         throw 'Buffer does not exist: "' . buf.bufnr . '"'
  537.                     elseif empty(bufname(buf.bufnr)) && getbufvar(buf.bufnr, '&buftype') != 'quickfix'
  538.                         if len(getbufline(buf.bufnr, '2')) != 0 || strlen(getbufline(buf.bufnr, '1')[0]) != 0
  539.                             echohl warningmsg | echomsg 'Skipping unnamed buffer: [' . buf.bufnr . ']' | echohl normal
  540.                         endif
  541.                     else
  542.                         let str = str . ' ' . fnameescape(bufname(buf.bufnr))
  543.                     endif
  544.                 endif
  545.             endif
  546.         endfor
  547.  
  548.         try
  549.             execute str
  550.         catch /^Vim\%((\a\+)\)\=:E\%(683\|480\):/ "E683: File name missing or invalid pattern --- E480: No match:
  551.             call s:RestoreArrowKeyBinds()
  552.             echomsg v:exception
  553.         endtry
  554.  
  555.         execute l:prefix . 'window'
  556.     finally
  557.         let &ignorecase = ignorecase
  558.     endtry
  559. endfunction
  560.  
  561. " Usage :GrepTabs [pattern] [matchCase] [matchWholeWord] [prefix]
  562. command! -nargs=* GrepTabs call s:GrepTabs(<f-args>)
  563.  
  564. " Usage :SearchTabs [matchCase] [matchWholeWord] [prefix]
  565. " Use the word under the cursor as the pattern.
  566. command! -nargs=* SearchTabs call s:CatchCancel('call s:GrepTabs(s:GetSearchText(), <f-args>)')
  567.  
  568. " Looks for a pattern in the buffers.
  569. " Usage :GrepBuffers [pattern] [matchCase] [matchWholeWord] [prefix]
  570. " If pattern is not specified then usage instructions will get printed.
  571. " If matchCase = '1' then exclude matches that do not have the same case. If matchCase = '0' then ignore case.
  572. " If prefix == 'c' then put results in the QuickFix list. If prefix == 'l' then put results in the location list for the current window.
  573. function! s:GrepBuffers(...)
  574.     if a:0 > 4
  575.         throw "Too many arguments"
  576.     endif
  577.  
  578.     if a:0 >= 1
  579.         let l:pattern = a:1
  580.     else
  581.         echo 'Usage :GrepBuffers [pattern] [matchCase] [matchWholeWord] [prefix]'
  582.         return
  583.     endif
  584.  
  585.     let l:matchCase = 0
  586.     if a:0 >= 2
  587.         if a:2 !~ '^\d\+$' || a:2 > 1 || a:2 < 0
  588.             throw "ArgumentException: matchCase value '" . a:2 . "' is not in the bounds [0,1]."
  589.         endif
  590.         let l:matchCase = a:2
  591.     endif
  592.  
  593.     let l:matchWholeWord = 0
  594.     if a:0 >= 3
  595.         if a:3 !~ '^\d\+$' || a:3 > 1 || a:3 < 0
  596.             throw "ArgumentException: matchWholeWord value '" . a:3 . "' is not in the bounds [0,1]."
  597.         endif
  598.         let l:matchWholeWord = a:3
  599.     endif
  600.  
  601.     let l:prefix = 'c'
  602.     if a:0 >= 4
  603.         if a:4 != 'c' && a:4 != 'l'
  604.             throw "ArgumentException: prefix value '" . a:4 . "' is not 'c' or 'l'."
  605.         endif
  606.         let l:prefix = a:4
  607.     endif
  608.  
  609.     let ignorecase = &ignorecase
  610.     let &ignorecase = l:matchCase == 0
  611.     try
  612.         call s:BindArrowKeysToQuickFixNavigation()
  613.  
  614.         let str = ''
  615.  
  616.         if l:prefix == 'l'
  617.             let str = 'l'
  618.         endif
  619.  
  620.         if l:matchWholeWord
  621.             let str = str . 'silent vimgrep /\<' . l:pattern . '\>/'
  622.         else
  623.             let str = str . 'silent vimgrep /' . l:pattern . '/'
  624.         endif
  625.  
  626.         for buf in getbufinfo()
  627.             if buflisted(buf.bufnr) " Skips unlisted buffers because they are not used for normal editing
  628.                 if !bufexists(buf.bufnr)
  629.                     throw 'Buffer does not exist: "' . buf.bufnr . '"'
  630.                 elseif empty(bufname(buf.bufnr)) && getbufvar(buf.bufnr, '&buftype') != 'quickfix'
  631.                     if len(getbufline(buf.bufnr, '2')) != 0 || strlen(getbufline(buf.bufnr, '1')[0]) != 0
  632.                         echohl warningmsg | echomsg 'Skipping unnamed buffer: [' . buf.bufnr . ']' | echohl normal
  633.                     endif
  634.                 else
  635.                     let str = str . ' ' . fnameescape(bufname(buf.bufnr))
  636.                 endif
  637.             endif
  638.         endfor
  639.  
  640.         try
  641.             execute str
  642.         catch /^Vim\%((\a\+)\)\=:E\%(683\|480\):/ "E683: File name missing or invalid pattern --- E480: No match:
  643.             call s:RestoreArrowKeyBinds()
  644.             echomsg v:exception
  645.         endtry
  646.  
  647.         execute l:prefix . 'window'
  648.     finally
  649.         let &ignorecase = ignorecase
  650.     endtry
  651. endfunction
  652.  
  653. " Usage :GrepBuffers [pattern] [matchCase] [matchWholeWord] [prefix]
  654. command! -nargs=* GrepBuffers call s:GrepBuffers(<f-args>)
  655.  
  656. " Usage :SearchBuffers [matchCase] [matchWholeWord] [prefix]
  657. " Use the word under the cursor as the pattern.
  658. command! -nargs=* SearchBuffers call s:CatchCancel('call s:GrepBuffers(s:GetSearchText(), <f-args>)')
  659.  
  660. " Looks for a pattern in the PWD and subdirectories of PWD.
  661. " Usage :GrepFiles [pattern] [matchCase] [matchWholeWord] [prefix]
  662. " If pattern is not specified then usage instructions will get printed.
  663. " If matchCase = '1' then exclude matches that do not have the same case. If matchCase = '0' then ignore case.
  664. " If prefix == 'c' then put results in the QuickFix list. If prefix == 'l' then put results in the location list for the current window.
  665. function! s:GrepFiles(...)
  666.     if a:0 > 4
  667.         throw "Too many arguments"
  668.     endif
  669.  
  670.     if a:0 >= 1
  671.         let l:pattern = a:1
  672.     else
  673.         echo 'Usage :GrepFiles [pattern] [matchCase] [matchWholeWord] [prefix]'
  674.         return
  675.     endif
  676.  
  677.     let l:matchCase = 0
  678.     if a:0 >= 2
  679.         if a:2 !~ '^\d\+$' || a:2 > 1 || a:2 < 0
  680.             throw "ArgumentException: matchCase value '" . a:2 . "' is not in the bounds [0,1]."
  681.         endif
  682.         let l:matchCase = a:2
  683.     endif
  684.  
  685.     let l:matchWholeWord = 0
  686.     if a:0 >= 3
  687.         if a:3 !~ '^\d\+$' || a:3 > 1 || a:3 < 0
  688.             throw "ArgumentException: matchWholeWord value '" . a:3 . "' is not in the bounds [0,1]."
  689.         endif
  690.         let l:matchWholeWord = a:3
  691.     endif
  692.  
  693.     let l:prefix = 'c'
  694.     if a:0 >= 4
  695.         if a:4 != 'c' && a:4 != 'l'
  696.             throw "ArgumentException: prefix value '" . a:4 . "' is not 'c' or 'l'."
  697.         endif
  698.         let l:prefix = a:4
  699.     endif
  700.  
  701.     let ignorecase = &ignorecase
  702.     let &ignorecase = l:matchCase == 0
  703.     try
  704.         call s:BindArrowKeysToQuickFixNavigation()
  705.  
  706.         let str = ''
  707.  
  708.         if l:prefix == 'l'
  709.             let str = 'l'
  710.         endif
  711.  
  712.         if l:matchWholeWord
  713.             let str = str . 'silent vimgrep /\<' . l:pattern . '\>/**'
  714.         else
  715.             let str = str . 'silent vimgrep /' . l:pattern . '/**'
  716.         endif
  717.  
  718.         try
  719.             execute str
  720.         catch /^Vim\%((\a\+)\)\=:E\%(683\|480\):/ "E683: File name missing or invalid pattern --- E480: No match:
  721.             call s:RestoreArrowKeyBinds()
  722.             echomsg v:exception
  723.         endtry
  724.  
  725.         execute l:prefix . 'window'
  726.     finally
  727.         let &ignorecase = ignorecase
  728.     endtry
  729. endfunction
  730.  
  731. " Usage :GrepFiles [pattern] [matchCase] [matchWholeWord] [prefix]
  732. command! -nargs=* GrepFiles call s:GrepFiles(<f-args>)
  733.  
  734. " Usage :SearchFiles [matchCase] [matchWholeWord] [prefix]
  735. " Use the word under the cursor as the pattern.
  736. command! -nargs=* SearchFiles call s:CatchCancel('call s:GrepFiles(s:GetSearchText(), <f-args>)')
  737.  
  738. function! s:GetSearchText(...)
  739.     if a:0 > 1
  740.         throw "Too many arguments"
  741.     endif
  742.  
  743.     let l:searchText = ''
  744.     if a:0 >= 1 && l:searchText != a:1
  745.         return s:GetTextInputFromUser("Search Target: ", a:1, 0)
  746.     endif
  747.  
  748.     let l:visualSelection = s:GetVisualSelection()
  749.     if len(l:visualSelection) > 0
  750.         call s:ClearVisualSelection()
  751.         return s:GetTextInputFromUser("Search Target: ", l:visualSelection, 0)
  752.     else
  753.         let l:wordUnderCursor = expand('<cword>')
  754.         if len(l:wordUnderCursor) > 0
  755.             return s:GetTextInputFromUser("Search Target: ", l:wordUnderCursor, 0)
  756.         else
  757.             return s:GetTextInputFromUser("Search Target: ", '', 0)
  758.         endif
  759.     endif
  760. endfunction
  761.  
  762. function! s:CatchCancel(searchFunction)
  763.     try
  764.         execute a:searchFunction
  765.     catch /user\ cancelled\ providing\ input/
  766.     endtry
  767. endfunction
  768.  
  769. " Provides a way to ask the user for text input.
  770. " The following editing keys are provided and work as expected in normal editors: Backspace, Delete, Left, Right, Home, End.
  771. " The user can cancel with Escape and submit text input with Enter.
  772. " You can also select text and do command-line copy|paste commands.
  773. "
  774. " Usage: let userInput = s:GetTextInputFromUser([inputRequest], [suggestedUserInput], [displayButtons])
  775. " Returns: Whatever the text state was when the user hit Enter. Can be ''.
  776. "
  777. " inputRequest - The question you want to ask the user, it can be '', and appears on the commandline left of the users entered text.
  778. " suggestedUserInput - Allows you to provide an initial version of the text you intend the user to modify and send back.
  779. " displayButtons - [0, 1] Display the "[Escape] [Enter]" buttons.
  780. "
  781. " Note: If the user cancels providing input, you need to handle the thrown exception like so: try | <code> | catch /user\ cancelled\ providing\ input/ | endtry
  782. "
  783. " Example: let userInput = s:GetTextInputFromUser("How many times have you been turned down for a job? ")
  784. "          let userInput = s:GetTextInputFromUser("Gender: ", "Attack Helicopter", 1)
  785. "
  786. "          If you don't like what the user is sending you, then just send it right back with a better request message.
  787. "          let pushTheButton = s:GetTextInputFromUser("Bomb North Korea? Say yes asshole! ", pushTheButton)
  788.  
  789. function! s:GetTextInputFromUser(...)
  790.     if a:0 > 3
  791.         throw "Too many arguments"
  792.     endif
  793.  
  794.     let inputRequest = ''
  795.     if a:0 >= 1
  796.        let inputRequest = a:1
  797.     endif
  798.  
  799.     let text = ''
  800.     if a:0 >= 2
  801.        let text = a:2
  802.     endif
  803.  
  804.     let displayButtons = 1
  805.     if a:0 >= 3
  806.         if a:3 !~ '^\d\+$' || a:3 > 1 || a:3 < 0
  807.             throw "ArgumentException: displayButtons value '" . a:3 . "' is not in the bounds [0,1]."
  808.         endif
  809.         let displayButtons = a:3
  810.     endif
  811.  
  812.     if displayButtons
  813.         echohl SpecialKey | echon "[Escape] "
  814.         echohl SpecialKey | echon "[Enter] "
  815.     endif
  816.  
  817.     call inputsave()
  818.  
  819.     echohl Question
  820.     let text = input(inputRequest, text)
  821.     echohl Normal
  822.  
  823.     call inputrestore()
  824.  
  825.     " Clear input prompt after input is entered
  826.     redraw!
  827.    
  828.     " If the user enters '' or hits escape
  829.     if text == ''
  830.         throw "user cancelled providing input"
  831.     endif
  832.  
  833.     return text
  834. endfunction
  835.  
  836. " SOURCE: https://stackoverflow.com/a/6271254/490748
  837. function! s:GetVisualSelection()
  838.     " Why is this not a built-in Vim script function?!
  839.     let [line_start, column_start] = getpos("'<")[1:2]
  840.     let [line_end, column_end] = getpos("'>")[1:2]
  841.     let lines = getline(line_start, line_end)
  842.     if len(lines) == 0
  843.         return ''
  844.     endif
  845.     let lines[-1] = lines[-1][: column_end - (&selection == 'inclusive' ? 1 : 2)]
  846.     let lines[0] = lines[0][column_start - 1:]
  847.     return join(lines, "\n")
  848. endfunction
  849.  
  850. function! s:ClearVisualSelection()
  851.     call setpos("'<", [0, 0, 0, 0])
  852.     call setpos("'>", [0, 0, 0, 0])
  853. endfunction
  854.  
  855. function! s:BindArrowKeysToQuickFixNavigation()
  856.     nnoremap <silent> <left>  :call WrapCommand('up', 'c')<CR><BAR>:cwindow<CR>|
  857.     nnoremap <silent> <right> :call WrapCommand('down', 'c')<CR><BAR>:cwindow<CR>|
  858.     nnoremap <silent> <up>    :call WrapCommand('up', 'c')<CR><BAR>:cwindow<CR>|
  859.     nnoremap <silent> <down>  :call WrapCommand('down', 'c')<CR><BAR>:cwindow<CR>|
  860.  
  861.     inoremap <silent> <left>  <Esc>:call WrapCommand('up', 'c')<CR><BAR>:cwindow<CR>|
  862.     inoremap <silent> <right> <Esc>:call WrapCommand('down', 'c')<CR><BAR>:cwindow<CR>|
  863.     inoremap <silent> <up>    <Esc>:call WrapCommand('up', 'c')<CR><BAR>:cwindow<CR>|
  864.     inoremap <silent> <down>  <Esc>:call WrapCommand('down', 'c')<CR><BAR>:cwindow<CR>|
  865. endfunction
  866.  
  867. function! s:RestoreArrowKeyBinds()
  868.     nnoremap <silent> <left>  <left>|
  869.     nnoremap <silent> <right> <right>|
  870.     nnoremap <silent> <up>    <up>|
  871.     nnoremap <silent> <down>  <down>|
  872.  
  873.     inoremap <silent> <left>  <left>|
  874.     inoremap <silent> <right> <right>|
  875.     inoremap <silent> <up>    <up>|
  876.     inoremap <silent> <down>  <down>|
  877. endfunction
  878.  
  879. " SOURCE: https://stackoverflow.com/questions/27198612/vim-location-list-how-to-go-to-first-location-if-at-last-location
  880. " Wrap :cnext/:cprevious and :lnext/:lprevious so that when a limit is encountered that it starts over at the opposite end of the list"
  881. function! WrapCommand(direction, prefix)
  882.     let l:hidden = &hidden
  883.     set nohidden " Disable to prevent creating lots of empty buffers when doing a vimgrep followed by QuickFix navigation commands
  884.     try
  885.         if a:direction == "up"
  886.             try
  887.                 execute a:prefix . "previous"
  888.             catch /^Vim\%((\a\+)\)\=:E553/
  889.                 execute a:prefix . "last"
  890.             catch /^Vim\%((\a\+)\)\=:E\%(776\|42\):/
  891.             endtry
  892.         elseif a:direction == "down"
  893.             try
  894.                 execute a:prefix . "next"
  895.             catch /^Vim\%((\a\+)\)\=:E553/
  896.                 execute a:prefix . "first"
  897.             catch /^Vim\%((\a\+)\)\=:E\%(776\|42\):/
  898.             endtry
  899.         endif
  900.     finally
  901.         let &hidden = l:hidden
  902.     endtry
  903. endfunction
  904.  
  905. "function! s:IsQuickFixAvailable()
  906. "    return !empty(getqflist())
  907. "endfunction
  908. "
  909. "function! IsQuickFixClosed()
  910. "     for win in getwininfo()
  911. "        if win.quickfix
  912. "            return 0
  913. "        endif
  914. "    endfor
  915. "    return 1
  916. "endfunction
  917.  
  918. " }}} Search windows, tabs, and files
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement