Update golden files
authorGreg Hurrell <greg@hurrell.net>
Wed, 3 May 2017 06:49:12 +0000 (23:49 -0700)
committerGreg Hurrell <greg@hurrell.net>
Wed, 3 May 2017 06:49:12 +0000 (23:49 -0700)
tests/fixtures/integration/ferret/golden/ast.golden
tests/fixtures/integration/ferret/golden/markdown.golden
tests/fixtures/integration/ferret/golden/plaintext.golden

index 2c8c4cbc10d548b7c61ee05cdb942a5641bd2faa..16e79c7b5ee4497167dcffaa2e3e2de2d9e0fa6b 100644 (file)
@@ -113,15 +113,11 @@ Project
       , Whitespace
       , Plaintext "(https://github.com/ggreer/the_silver_searcher),"
       , Whitespace
-      , Plaintext "Ack"
-      , Whitespace
-      , Plaintext "(http://beyondgrep.com/),"
-      , Whitespace
       , Plaintext "or"
       , Whitespace
-      , Plaintext "Grep"
+      , Plaintext "Ack"
       , Whitespace
-      , Plaintext "(http://www.gnu.org/software/grep/)."
+      , Plaintext "(http://beyondgrep.com/)."
       , Whitespace
       , Plaintext "Support"
       , Whitespace
@@ -172,6 +168,34 @@ Project
       , Plaintext "special"
       , Whitespace
       , Plaintext "escaping."
+      , Whitespace
+      , Plaintext "On"
+      , Whitespace
+      , Plaintext "Vim"
+      , Whitespace
+      , Plaintext "version"
+      , Whitespace
+      , Plaintext "8"
+      , Whitespace
+      , Plaintext "or"
+      , Whitespace
+      , Plaintext "higher,"
+      , Whitespace
+      , Plaintext "searches"
+      , Whitespace
+      , Plaintext "are"
+      , Whitespace
+      , Plaintext "performed"
+      , Whitespace
+      , Plaintext "asynchronously"
+      , Whitespace
+      , Plaintext "(without"
+      , Whitespace
+      , Plaintext "blocking"
+      , Whitespace
+      , Plaintext "the"
+      , Whitespace
+      , Plaintext "UI)."
       ]
   , Paragraph
       [ Plaintext "Shortcut"
@@ -284,6 +308,44 @@ Project
       , Link ":Lack"
       , Plaintext "."
       ]
+  , Paragraph
+      [ Link ":Back"
+      , Whitespace
+      , Plaintext "and"
+      , Whitespace
+      , Link ":Black"
+      , Whitespace
+      , Plaintext "are"
+      , Whitespace
+      , Plaintext "analogous"
+      , Whitespace
+      , Plaintext "to"
+      , Whitespace
+      , Link ":Ack"
+      , Whitespace
+      , Plaintext "and"
+      , Whitespace
+      , Link ":Lack"
+      , Plaintext ","
+      , Whitespace
+      , Plaintext "but"
+      , Whitespace
+      , Plaintext "scoped"
+      , Whitespace
+      , Plaintext "to"
+      , Whitespace
+      , Plaintext "search"
+      , Whitespace
+      , Plaintext "within"
+      , Whitespace
+      , Plaintext "currently"
+      , Whitespace
+      , Plaintext "open"
+      , Whitespace
+      , Plaintext "buffers"
+      , Whitespace
+      , Plaintext "only."
+      ]
   , Paragraph
       [ Plaintext "Finally,"
       , Whitespace
@@ -307,6 +369,24 @@ Project
       , Whitespace
       , Plaintext "searching"
       , Whitespace
+      , Plaintext "on"
+      , Whitespace
+      , Plaintext "older"
+      , Whitespace
+      , Plaintext "versions"
+      , Whitespace
+      , Plaintext "of"
+      , Whitespace
+      , Plaintext "Vim"
+      , Whitespace
+      , Plaintext "(prior"
+      , Whitespace
+      , Plaintext "to"
+      , Whitespace
+      , Plaintext "version"
+      , Whitespace
+      , Plaintext "8),"
+      , Whitespace
       , Plaintext "despite"
       , Whitespace
       , Plaintext "the"
@@ -396,7 +476,11 @@ Project
       , Plaintext "of"
       , Whitespace
       , Link ":Ack"
-      , Plaintext "."
+      , Whitespace
+      , Plaintext "(or"
+      , Whitespace
+      , Link ":Back"
+      , Plaintext ")."
       ]
   , SubheadingAnnotation "3. Quickfix listing enhancements"
   , Paragraph
@@ -1018,7 +1102,12 @@ Project
                   [ LetStatement
                       { letLexpr = "l:command" , letValue = "s:parse(a:000)" }
                   , GenericStatement "call ferret#private#hlsearch()"
-                  , GenericStatement "if empty(&grepprg)"
+                  , LetStatement
+                      { letLexpr = "l:executable"
+                      , letValue = "ferret#private#executable()"
+                      }
+                  , GenericStatement "if empty(l:executable)"
+                  , GenericStatement "call ferret#private#installprompt()"
                   , GenericStatement "return"
                   , GenericStatement "endif"
                   , GenericStatement "if ferret#private#async()"
@@ -1031,6 +1120,54 @@ Project
                   , GenericStatement "endif"
                   ]
               }
+          , FunctionDeclaration
+              { functionBang = True
+              , functionName = "ferret#private#buflist"
+              , functionArguments = ArgumentList []
+              , functionAttributes = [ "abort" ]
+              , functionBody =
+                  [ LetStatement
+                      { letLexpr = "l:buflist"
+                      , letValue = "getbufinfo({'buflisted': 1})"
+                      }
+                  , LetStatement
+                      { letLexpr = "l:bufpaths"
+                      , letValue =
+                          "filter(map(l:buflist, 'v:val.name'), 'v:val !=# \"\"')"
+                      }
+                  , GenericStatement "return l:bufpaths"
+                  ]
+              }
+          , FunctionDeclaration
+              { functionBang = True
+              , functionName = "ferret#private#back"
+              , functionArguments = ArgumentList [ Argument "..." ]
+              , functionAttributes = [ "abort" ]
+              , functionBody =
+                  [ GenericStatement
+                      "call call('ferret#private#ack', a:000 + ferret#private#buflist())"
+                  ]
+              }
+          , FunctionDeclaration
+              { functionBang = True
+              , functionName = "ferret#private#black"
+              , functionArguments = ArgumentList [ Argument "..." ]
+              , functionAttributes = [ "abort" ]
+              , functionBody =
+                  [ GenericStatement
+                      "call call('ferret#private#lack', a:000 + ferret#private#buflist())"
+                  ]
+              }
+          , FunctionDeclaration
+              { functionBang = True
+              , functionName = "ferret#private#installprompt"
+              , functionArguments = ArgumentList []
+              , functionAttributes = [ "abort" ]
+              , functionBody =
+                  [ GenericStatement
+                      "call ferret#private#error( 'Unable to find suitable executable; install rg, ag, ack or ack-grep' )"
+                  ]
+              }
           , FunctionDeclaration
               { functionBang = True
               , functionName = "ferret#private#lack"
@@ -1040,7 +1177,12 @@ Project
                   [ LetStatement
                       { letLexpr = "l:command" , letValue = "s:parse(a:000)" }
                   , GenericStatement "call ferret#private#hlsearch()"
-                  , GenericStatement "if empty(&grepprg)"
+                  , LetStatement
+                      { letLexpr = "l:executable"
+                      , letValue = "ferret#private#executable()"
+                      }
+                  , GenericStatement "if empty(l:executable)"
+                  , GenericStatement "call ferret#private#installprompt()"
                   , GenericStatement "return"
                   , GenericStatement "endif"
                   , GenericStatement "if ferret#private#async()"
@@ -1063,7 +1205,7 @@ Project
                       { letLexpr = "l:hlsearch"
                       , letValue = "get(g:, 'FerretHlsearch', &hlsearch)"
                       }
-                  , GenericStatement "if l:hlsearch"
+                  , GenericStatement "if l:hlsearch && exists('g:ferret_lastsearch')"
                   , LetStatement
                       { letLexpr = "@/" , letValue = "g:ferret_lastsearch" }
                   , GenericStatement
@@ -1098,6 +1240,11 @@ Project
                   , GenericStatement "if l:options !~# 'g'"
                   , LetStatement { letLexpr = "l:options ." , letValue = "'g'" }
                   , GenericStatement "endif"
+                  , LetStatement
+                      { letLexpr = "l:cfdo"
+                      , letValue = "has('listcmds') && exists(':cfdo') == 2"
+                      }
+                  , GenericStatement "if !l:cfdo"
                   , LetStatement
                       { letLexpr = "l:filenames" , letValue = "ferret#private#qargs()" }
                   , GenericStatement "if l:filenames ==# ''"
@@ -1106,9 +1253,15 @@ Project
                   , GenericStatement "return"
                   , GenericStatement "endif"
                   , GenericStatement "execute 'args' l:filenames"
+                  , GenericStatement "endif"
                   , GenericStatement "call ferret#private#autocmd('FerretWillWrite')"
+                  , GenericStatement "if l:cfdo"
+                  , GenericStatement
+                      "execute 'cfdo' '%s' . l:pattern . l:options . ' | update'"
+                  , GenericStatement "else"
                   , GenericStatement
                       "execute 'argdo' '%s' . l:pattern . l:options . ' | update'"
+                  , GenericStatement "endif"
                   , GenericStatement "call ferret#private#autocmd('FerretDidWrite')"
                   ]
               }
@@ -1146,7 +1299,31 @@ Project
               , functionAttributes = [ "abort" ]
               , functionBody =
                   [ GenericStatement
-                      "return ferret#private#complete('Ack', a:arglead, a:cmdline, a:cursorpos)"
+                      "return ferret#private#complete('Ack', a:arglead, a:cmdline, a:cursorpos, 1)"
+                  ]
+              }
+          , FunctionDeclaration
+              { functionBang = True
+              , functionName = "ferret#private#backcomplete"
+              , functionArguments =
+                  ArgumentList
+                    [ Argument "arglead" , Argument "cmdline" , Argument "cursorpos" ]
+              , functionAttributes = [ "abort" ]
+              , functionBody =
+                  [ GenericStatement
+                      "return ferret#private#complete('Lack', a:arglead, a:cmdline, a:cursorpos, 0)"
+                  ]
+              }
+          , FunctionDeclaration
+              { functionBang = True
+              , functionName = "ferret#private#blackcomplete"
+              , functionArguments =
+                  ArgumentList
+                    [ Argument "arglead" , Argument "cmdline" , Argument "cursorpos" ]
+              , functionAttributes = [ "abort" ]
+              , functionBody =
+                  [ GenericStatement
+                      "return ferret#private#complete('Lack', a:arglead, a:cmdline, a:cursorpos, 0)"
                   ]
               }
           , FunctionDeclaration
@@ -1158,21 +1335,32 @@ Project
               , functionAttributes = [ "abort" ]
               , functionBody =
                   [ GenericStatement
-                      "return ferret#private#complete('Lack', a:arglead, a:cmdline, a:cursorpos)"
+                      "return ferret#private#complete('Lack', a:arglead, a:cmdline, a:cursorpos, 1)"
+                  ]
+              }
+          , FunctionDeclaration
+              { functionBang = True
+              , functionName = "ferret#private#executable_name"
+              , functionArguments = ArgumentList []
+              , functionAttributes = []
+              , functionBody =
+                  [ LetStatement
+                      { letLexpr = "l:executable"
+                      , letValue = "ferret#private#executable()"
+                      }
+                  , LetStatement
+                      { letLexpr = "l:binary"
+                      , letValue = "matchstr(l:executable, '\\v\\w+')"
+                      }
                   ]
               }
-          , GenericStatement "if executable('ag')"
-          , LetStatement { letLexpr = "s:executable" , letValue = "'ag'" }
-          , GenericStatement "elseif executable('ack')"
-          , LetStatement { letLexpr = "s:executable" , letValue = "'ack'" }
-          , GenericStatement "elseif executable('grep')"
-          , LetStatement { letLexpr = "s:executable" , letValue = "'grep'" }
-          , GenericStatement "else"
-          , LetStatement { letLexpr = "s:executable" , letValue = "''" }
-          , GenericStatement "endif"
           , LetStatement { letLexpr = "s:options " , letValue = "{" }
           , GenericStatement
-              "\\ 'ack': [ '--ignore-ack-defaults', '--ignore-case', '--ignore-dir', '--ignore-directory', '--invert-match', '--known-types', '--literal', '--no-recurse', '--recurse', '--sort-files', '--type', '--word-regexp', '-1', '-Q', '-R', '-i', '-k', '-r', '-v', '-w', ], 'ag': [ '--all-types', '--all-text', '--case-sensitive', '--depth', '--follow', '--ignore', '--ignore-case', '--ignore-dir', '--invert-match', '--literal', '--max-count', '--skip-vcs-ignores', '--unrestricted', '--word-regexp', '-Q', '-U', '-a', '-i', '-m', '-s', '-t', '-u', '-v', '-w' ] }"
+              "\\ 'ack': [ '--ignore-ack-defaults', '--ignore-case', '--ignore-dir', '--ignore-directory', '--invert-match', '--known-types', '--literal', '--no-recurse', '--recurse', '--sort-files', '--type', '--word-regexp', '-1', '-Q', '-R', '-i', '-k', '-r', '-v', '-w', ], 'ag': [ '--all-types', '--all-text', '--case-sensitive', '--depth', '--follow', '--ignore', '--ignore-case', '--ignore-dir', '--invert-match', '--literal', '--max-count', '--skip-vcs-ignores', '--unrestricted', '--word-regexp', '-Q', '-U', '-a', '-i', '-m', '-s', '-t', '-u', '-v', '-w' ], 'rg': [ '--case-sensitive', '--files-with-matches', '--follow', '--glob', '--hidden', '--ignore-case', '--invert-match', '--max-count', '--maxdepth', '--mmap', '--no-ignore', '--no-ignore-parent', '--no-ignore-vcs', '--no-mmap', '--regexp', '--smart-case', '--text', '--threads', '--type', '--type-not', '--unrestricted', '--word-regexp', '-F', '-L', '-R', '-T', '-a', '-e', '-g', '-i', '-j', '-m', '-s', '-t', '-u', '-v', '-w' ] }"
+          , LetStatement
+              { letLexpr = "s:options['ack-grep']"
+              , letValue = "s:options['ack']"
+              }
           , FunctionDeclaration
               { functionBang = True
               , functionName = "ferret#private#complete"
@@ -1182,6 +1370,7 @@ Project
                     , Argument "arglead"
                     , Argument "cmdline"
                     , Argument "cursorpos"
+                    , Argument "files"
                     ]
               , functionAttributes = [ "abort" ]
               , functionBody =
@@ -1203,12 +1392,12 @@ Project
                   , GenericStatement "if a:cursorpos <= l:position"
                   , LetStatement
                       { letLexpr = "l:options"
-                      , letValue = "get(s:options, s:executable, [])"
+                      , letValue = "get(s:options, ferret#private#executable_name(), [])"
                       }
                   , GenericStatement
                       "return filter(l:options, 'match(v:val, l:stripped) == 0')"
                   , GenericStatement "endif"
-                  , GenericStatement "elseif l:pattern_seen"
+                  , GenericStatement "elseif l:pattern_seen && a:files"
                   , GenericStatement "if a:cursorpos <= l:position"
                   , GenericStatement "return glob(a:arglead . '*', 1, 1)"
                   , GenericStatement "end"
@@ -1274,17 +1463,100 @@ Project
                       { letLexpr = "&selection" , letValue = "l:selection" }
                   ]
               }
-          ]
-      , Unit
-          [ LetStatement { letLexpr = "s:jobs" , letValue = "{}" }
+          , LetStatement
+              { letLexpr = "s:force"
+              , letValue = "get(g:, 'FerretExecutable', 'rg,ag,ack,ack-grep')"
+              }
+          , LetStatement { letLexpr = "s:executables" , letValue = "{" }
+          , GenericStatement
+              "\\ 'rg': 'rg --vimgrep --no-heading', 'ag': 'ag', 'ack': 'ack --column --with-filename', 'ack-grep': 'ack-grep --column --with-filename' }"
+          , LetStatement { letLexpr = "s:init_done" , letValue = "0" }
           , FunctionDeclaration
               { functionBang = True
-              , functionName = "s:channel_id"
-              , functionArguments = ArgumentList [ Argument "channel" ]
-              , functionAttributes = []
+              , functionName = "ferret#private#init"
+              , functionArguments = ArgumentList []
+              , functionAttributes = [ "abort" ]
+              , functionBody =
+                  [ GenericStatement "if s:init_done"
+                  , GenericStatement "return"
+                  , GenericStatement "endif"
+                  , GenericStatement
+                      "if executable('rg') && match(system('rg --help'), '--max-columns') != -1"
+                  , LetStatement
+                      { letLexpr = "s:executables['rg']."
+                      , letValue = "' --max-columns 4096'"
+                      }
+                  , GenericStatement "endif"
+                  , GenericStatement "if executable('ag')"
+                  , LetStatement
+                      { letLexpr = "s:ag_help" , letValue = "system('ag --help')" }
+                  , GenericStatement "if match(s:ag_help, '--vimgrep') != -1"
+                  , LetStatement
+                      { letLexpr = "s:executables['ag']." , letValue = "' --vimgrep'" }
+                  , GenericStatement "else"
+                  , LetStatement
+                      { letLexpr = "s:executables['ag']." , letValue = "' --column'" }
+                  , GenericStatement "endif"
+                  , GenericStatement "if match(s:ag_help, '--width') != -1"
+                  , LetStatement
+                      { letLexpr = "s:executables['ag']."
+                      , letValue = "' --width 4096'"
+                      }
+                  , GenericStatement "endif"
+                  , GenericStatement "endif"
+                  , LetStatement
+                      { letLexpr = "l:executable"
+                      , letValue = "ferret#private#executable()"
+                      }
+                  , GenericStatement "if !empty(l:executable)"
+                  , LetStatement
+                      { letLexpr = "&grepprg" , letValue = "l:executable" }
+                  , LetStatement
+                      { letLexpr = "&grepformat" , letValue = "g:FerretFormat" }
+                  , GenericStatement "endif"
+                  , LetStatement { letLexpr = "s:init_done" , letValue = "1" }
+                  ]
+              }
+          , FunctionDeclaration
+              { functionBang = True
+              , functionName = "ferret#private#executable"
+              , functionArguments = ArgumentList []
+              , functionAttributes = [ "abort" ]
               , functionBody =
-                  [ GenericStatement "return matchstr(a:channel, '\\d\\+')" ]
+                  [ LetStatement
+                      { letLexpr = "l:valid" , letValue = "keys(s:executables)" }
+                  , LetStatement
+                      { letLexpr = "l:executables"
+                      , letValue = "split(s:force, '\\v\\s*,\\s*')"
+                      }
+                  , LetStatement
+                      { letLexpr = "l:executables"
+                      , letValue = "filter(l:executables, 'index(l:valid, v:val) != -1')"
+                      }
+                  , GenericStatement "if index(l:executables, 'rg') == -1"
+                  , GenericStatement "call add(l:executables, 'rg')"
+                  , GenericStatement "endif"
+                  , GenericStatement "if index(l:executables, 'ag') == -1"
+                  , GenericStatement "call add(l:executables, 'ag')"
+                  , GenericStatement "endif"
+                  , GenericStatement "if index(l:executables, 'ack') == -1"
+                  , GenericStatement "call add(l:executables, 'ack')"
+                  , GenericStatement "endif"
+                  , GenericStatement "if index(l:executables, 'ack-grep') == -1"
+                  , GenericStatement "call add(l:executables, 'ack-grep')"
+                  , GenericStatement "endif"
+                  , GenericStatement "for l:executable in l:executables"
+                  , GenericStatement "if executable(l:executable)"
+                  , GenericStatement "return s:executables[l:executable]"
+                  , GenericStatement "endif"
+                  , GenericStatement "endfor"
+                  , GenericStatement "return ''"
+                  ]
               }
+          , GenericStatement "call ferret#private#init()"
+          ]
+      , Unit
+          [ LetStatement { letLexpr = "s:jobs" , letValue = "{}" }
           , FunctionDeclaration
               { functionBang = True
               , functionName = "s:info_from_channel"
@@ -1293,7 +1565,7 @@ Project
               , functionBody =
                   [ LetStatement
                       { letLexpr = "l:channel_id"
-                      , letValue = "s:channel_id(a:channel)"
+                      , letValue = "ch_info(a:channel)['id']"
                       }
                   , GenericStatement "if has_key(s:jobs, l:channel_id)"
                   , GenericStatement "return s:jobs[l:channel_id]"
@@ -1311,20 +1583,21 @@ Project
                   , GenericStatement
                       "call ferret#private#autocmd('FerretAsyncStart')"
                   , LetStatement
-                      { letLexpr = "l:command_and_args "
-                      , letValue = "extend(split(&grepprg), a:command)"
+                      { letLexpr = "l:command_and_args"
+                      , letValue =
+                          "extend(split(ferret#private#executable()), a:command)"
                       }
                   , LetStatement
                       { letLexpr = "l:job"
                       , letValue = "job_start(l:command_and_args, {"
                       }
                   , GenericStatement
-                      "\\ 'err_cb': 'ferret#private#async#err_cb', 'out_cb': 'ferret#private#async#out_cb', 'close_cb': 'ferret#private#async#close_cb', 'err_mode': 'raw', 'out_mode': 'raw' })"
+                      "\\ 'in_io': 'null', 'err_cb': 'ferret#private#async#err_cb', 'out_cb': 'ferret#private#async#out_cb', 'close_cb': 'ferret#private#async#close_cb', 'err_mode': 'raw', 'out_mode': 'raw' })"
                   , LetStatement
                       { letLexpr = "l:channel" , letValue = "job_getchannel(l:job)" }
                   , LetStatement
                       { letLexpr = "l:channel_id"
-                      , letValue = "s:channel_id(l:channel)"
+                      , letValue = "ch_info(l:channel)['id']"
                       }
                   , LetStatement
                       { letLexpr = "s:jobs[l:channel_id]" , letValue = "{" }
@@ -1333,7 +1606,7 @@ Project
                   ]
               }
           , LetStatement
-              { letLexpr = "s:max_line_length" , letValue = "32768" }
+              { letLexpr = "s:max_line_length" , letValue = "4096" }
           , FunctionDeclaration
               { functionBang = True
               , functionName = "ferret#private#async#err_cb"
@@ -1346,41 +1619,37 @@ Project
                       , letValue = "s:info_from_channel(a:channel)"
                       }
                   , GenericStatement "if type(l:info) == 4"
-                  , LetStatement { letLexpr = "l:start" , letValue = "0" }
-                  , GenericStatement "while 1"
                   , LetStatement
-                      { letLexpr = "l:idx" , letValue = "match(a:msg, '\\n', l:start)" }
-                  , GenericStatement "if l:idx==-1"
+                      { letLexpr = "l:lines" , letValue = "split(a:msg, '\\n', 1)" }
+                  , LetStatement { letLexpr = "l:count" , letValue = "len(l:lines)" }
+                  , GenericStatement "for l:i in range(l:count)"
+                  , LetStatement { letLexpr = "l:line" , letValue = "l:lines[l:i]" }
                   , GenericStatement
-                      "if l:info.pending_error_length < s:max_line_length"
-                  , LetStatement
-                      { letLexpr = "l:rest" , letValue = "strpart(a:msg, l:start)" }
-                  , LetStatement
-                      { letLexpr = "l:length" , letValue = "strlen(l:rest)" }
-                  , LetStatement
-                      { letLexpr = "l:info.pending_error." , letValue = "l:rest" }
-                  , LetStatement
-                      { letLexpr = "l:info.pending_error_length+"
-                      , letValue = "l:length"
-                      }
-                  , GenericStatement "endif"
-                  , GenericStatement "break"
-                  , GenericStatement "else"
+                      "if l:i != l:count - 1 || l:line == '' && l:info.pending_error_length"
                   , GenericStatement
                       "if l:info.pending_error_length < s:max_line_length"
-                  , LetStatement
-                      { letLexpr = "l:info.pending_error."
-                      , letValue = "strpart(a:msg, l:start, l:idx - l:start)"
-                      }
-                  , GenericStatement "endif"
+                  , LetStatement { letLexpr = "l:rest" , letValue = "strpart(" }
+                  , GenericStatement
+                      "\\ l:line, 0, s:max_line_length - l:info.pending_error_length )"
+                  , GenericStatement
+                      "call add(l:info.errors, l:info.pending_error . l:rest)"
+                  , GenericStatement "else"
                   , GenericStatement "call add(l:info.errors, l:info.pending_error)"
+                  , GenericStatement "endif"
                   , LetStatement
                       { letLexpr = "l:info.pending_error" , letValue = "''" }
                   , LetStatement
                       { letLexpr = "l:info.pending_error_length" , letValue = "0" }
+                  , GenericStatement
+                      "elseif l:info.pending_error_length < s:max_line_length"
+                  , LetStatement
+                      { letLexpr = "l:info.pending_error." , letValue = "l:line" }
+                  , LetStatement
+                      { letLexpr = "l:info.pending_error_length+"
+                      , letValue = "strlen(l:line)"
+                      }
                   , GenericStatement "endif"
-                  , LetStatement { letLexpr = "l:start" , letValue = "l:idx + 1" }
-                  , GenericStatement "endwhile"
+                  , GenericStatement "endfor"
                   , GenericStatement "endif"
                   ]
               }
@@ -1396,41 +1665,37 @@ Project
                       , letValue = "s:info_from_channel(a:channel)"
                       }
                   , GenericStatement "if type(l:info) == 4"
-                  , LetStatement { letLexpr = "l:start" , letValue = "0" }
-                  , GenericStatement "while 1"
                   , LetStatement
-                      { letLexpr = "l:idx" , letValue = "match(a:msg, '\\n', l:start)" }
-                  , GenericStatement "if l:idx==-1"
+                      { letLexpr = "l:lines" , letValue = "split(a:msg, '\\n', 1)" }
+                  , LetStatement { letLexpr = "l:count" , letValue = "len(l:lines)" }
+                  , GenericStatement "for l:i in range(l:count)"
+                  , LetStatement { letLexpr = "l:line" , letValue = "l:lines[l:i]" }
                   , GenericStatement
-                      "if l:info.pending_output_length < s:max_line_length"
-                  , LetStatement
-                      { letLexpr = "l:rest" , letValue = "strpart(a:msg, l:start)" }
-                  , LetStatement
-                      { letLexpr = "l:length" , letValue = "strlen(l:rest)" }
-                  , LetStatement
-                      { letLexpr = "l:info.pending_output." , letValue = "l:rest" }
-                  , LetStatement
-                      { letLexpr = "l:info.pending_output_length+"
-                      , letValue = "l:length"
-                      }
-                  , GenericStatement "endif"
-                  , GenericStatement "break"
-                  , GenericStatement "else"
+                      "if l:i != l:count - 1 || l:line == '' && l:info.pending_output_length"
                   , GenericStatement
                       "if l:info.pending_output_length < s:max_line_length"
-                  , LetStatement
-                      { letLexpr = "l:info.pending_output."
-                      , letValue = "strpart(a:msg, l:start, l:idx - l:start)"
-                      }
-                  , GenericStatement "endif"
+                  , LetStatement { letLexpr = "l:rest" , letValue = "strpart(" }
+                  , GenericStatement
+                      "\\ l:line, 0, s:max_line_length - l:info.pending_output_length )"
+                  , GenericStatement
+                      "call add(l:info.output, l:info.pending_output . l:rest)"
+                  , GenericStatement "else"
                   , GenericStatement "call add(l:info.output, l:info.pending_output)"
+                  , GenericStatement "endif"
                   , LetStatement
                       { letLexpr = "l:info.pending_output" , letValue = "''" }
                   , LetStatement
                       { letLexpr = "l:info.pending_output_length" , letValue = "0" }
+                  , GenericStatement
+                      "elseif l:info.pending_output_length < s:max_line_length"
+                  , LetStatement
+                      { letLexpr = "l:info.pending_output." , letValue = "l:line" }
+                  , LetStatement
+                      { letLexpr = "l:info.pending_output_length+"
+                      , letValue = "strlen(l:line)"
+                      }
                   , GenericStatement "endif"
-                  , LetStatement { letLexpr = "l:start" , letValue = "l:idx + 1" }
-                  , GenericStatement "endwhile"
+                  , GenericStatement "endfor"
                   , GenericStatement "endif"
                   ]
               }
@@ -1452,7 +1717,7 @@ Project
                   , GenericStatement "call win_gotoid(l:info.window)"
                   , GenericStatement "endif"
                   , GenericStatement
-                      "call s:finalize_search(l:info.output, l:info.ack)"
+                      "call ferret#private#shared#finalize_search(l:info.output, l:info.ack)"
                   , GenericStatement "for l:error in l:info.errors"
                   , GenericStatement "unsilent echomsg l:error"
                   , GenericStatement "endfor"
@@ -1469,7 +1734,7 @@ Project
                   , LetStatement
                       { letLexpr = "l:info" , letValue = "s:jobs[l:channel_id]" }
                   , GenericStatement
-                      "call s:finalize_search(l:info.output, l:info.ack)"
+                      "call ferret#private#shared#finalize_search(l:info.output, l:info.ack)"
                   , GenericStatement "endfor"
                   ]
               }
@@ -1500,28 +1765,9 @@ Project
               , functionAttributes = [ "abort" ]
               , functionBody = [ GenericStatement "return s:jobs" ]
               }
-          , FunctionDeclaration
-              { functionBang = True
-              , functionName = "s:finalize_search"
-              , functionArguments =
-                  ArgumentList [ Argument "output" , Argument "ack" ]
-              , functionAttributes = []
-              , functionBody =
-                  [ GenericStatement "if a:ack"
-                  , GenericStatement "cexpr a:output"
-                  , GenericStatement
-                      "execute get(g:, 'FerretQFHandler', 'botright cwindow')"
-                  , GenericStatement "call ferret#private#post('qf')"
-                  , GenericStatement "else"
-                  , LexprStatement { lexprBang = False , lexprExpr = "a:output" }
-                  , GenericStatement "execute get(g:, 'FerretLLHandler', 'lwindow')"
-                  , GenericStatement "call ferret#private#post('location')"
-                  , GenericStatement "endif"
-                  ]
-              }
-          ]
-      , Unit
-          [ FunctionDeclaration
+          ]
+      , Unit
+          [ FunctionDeclaration
               { functionBang = True
               , functionName = "ferret#private#dispatch#search"
               , functionArguments = ArgumentList [ Argument "command" ]
@@ -1543,11 +1789,10 @@ Project
                   , GenericStatement "try"
                   , LetStatement
                       { letLexpr = "&l:makeprg"
-                      , letValue = "&grepprg . ' ' . a:command"
+                      , letValue = "ferret#private#executable() . ' ' . a:command"
                       }
                   , LetStatement
-                      { letLexpr = "&l:errorformat" , letValue = "&grepformat" }
-                  , GenericStatement "echomsg &l:makeprg"
+                      { letLexpr = "&l:errorformat" , letValue = "g:FerretFormat" }
                   , GenericStatement "Make"
                   , GenericStatement "catch"
                   , GenericStatement "call ferret#private#clearautocmd()"
@@ -1565,24 +1810,49 @@ Project
       , Unit
           [ FunctionDeclaration
               { functionBang = True
-              , functionName = "s:finalize_search"
+              , functionName = "ferret#private#shared#finalize_search"
               , functionArguments =
                   ArgumentList [ Argument "output" , Argument "ack" ]
               , functionAttributes = []
               , functionBody =
-                  [ GenericStatement "if a:ack"
-                  , GenericStatement "cexpr a:output"
+                  [ LetStatement
+                      { letLexpr = "l:original_errorformat" , letValue = "&errorformat" }
+                  , GenericStatement "try"
+                  , LetStatement
+                      { letLexpr = "&errorformat" , letValue = "g:FerretFormat" }
+                  , GenericStatement "if a:ack"
+                  , GenericStatement "call s:swallow('cexpr a:1', a:output)"
                   , GenericStatement
                       "execute get(g:, 'FerretQFHandler', 'botright cwindow')"
                   , GenericStatement "call ferret#private#post('qf')"
                   , GenericStatement "else"
-                  , LexprStatement { lexprBang = False , lexprExpr = "a:output" }
+                  , GenericStatement "call s:swallow('lexpr a:1', a:output)"
                   , GenericStatement "execute get(g:, 'FerretLLHandler', 'lwindow')"
                   , GenericStatement "call ferret#private#post('location')"
                   , GenericStatement "endif"
+                  , GenericStatement "finally"
+                  , LetStatement
+                      { letLexpr = "&errorformat" , letValue = "l:original_errorformat" }
+                  , GenericStatement "endtry"
                   ]
               }
           , FunctionDeclaration
+              { functionBang = True
+              , functionName = "s:swallow"
+              , functionArguments =
+                  ArgumentList [ Argument "executable" , Argument "..." ]
+              , functionAttributes = []
+              , functionBody =
+                  [ GenericStatement "try"
+                  , GenericStatement "execute a:executable"
+                  , GenericStatement "catch"
+                  , GenericStatement "echomsg 'Caught: ' . v:exception"
+                  , GenericStatement "endtry"
+                  ]
+              }
+          ]
+      , Unit
+          [ FunctionDeclaration
               { functionBang = True
               , functionName = "ferret#private#vanilla#search"
               , functionArguments =
@@ -1590,10 +1860,15 @@ Project
               , functionAttributes = [ "abort" ]
               , functionBody =
                   [ LetStatement
+                      { letLexpr = "l:executable"
+                      , letValue = "ferret#private#executable()"
+                      }
+                  , LetStatement
                       { letLexpr = "l:output"
-                      , letValue = "system(&grepprg . ' ' . a:command)"
+                      , letValue = "system(l:executable . ' ' . a:command)"
                       }
-                  , GenericStatement "call s:finalize_search(l:output, a:ack)"
+                  , GenericStatement
+                      "call ferret#private#shared#finalize_search(l:output, a:ack)"
                   ]
               }
           ]
@@ -1642,38 +1917,17 @@ Project
           , LetStatement
               { letLexpr = "s:cpoptions " , letValue = "&cpoptions" }
           , GenericStatement "set cpoptions&vim"
-          , GenericStatement
-              "if executable('ag') \" The Silver Searcher: faster than ack."
-          , LetStatement
-              { letLexpr = "s:ackprg " , letValue = "'ag --vimgrep'" }
-          , GenericStatement
-              "elseif executable('ack') \" Ack: better than grep."
-          , LetStatement
-              { letLexpr = "s:ackprg "
-              , letValue = "'ack --column --with-filename'"
-              }
-          , GenericStatement
-              "elseif executable('grep') \" Grep: it's just grep."
-          , LetStatement
-              { letLexpr = "s:ackprg "
-              , letValue = "&grepprg \" default is: grep -n $* /dev/null"
-              }
-          , GenericStatement "endif"
-          , GenericStatement "if !empty(s:ackprg)"
-          , LetStatement { letLexpr = "&grepprg" , letValue = "s:ackprg" }
-          , GenericStatement "set grepformat=%f:%l:%c:%m"
-          , GenericStatement "endif"
-          , GenericStatement "if has('autocmd')"
-          , GenericStatement "augroup Ferret"
-          , GenericStatement "autocmd!"
-          , GenericStatement "autocmd QuickFixCmdPost [^l]* nested cwindow"
-          , GenericStatement "autocmd QuickFixCmdPost l* nested lwindow"
-          , GenericStatement "augroup END"
+          , GenericStatement "if !get(g:, 'FerretLazyInit', 1)"
+          , GenericStatement "call ferret#private#init()"
           , GenericStatement "endif"
           , GenericStatement
               "command! -nargs=+ -complete=customlist,ferret#private#ackcomplete Ack call ferret#private#ack(<f-args>)"
           , GenericStatement
               "command! -nargs=+ -complete=customlist,ferret#private#lackcomplete Lack call ferret#private#lack(<f-args>)"
+          , GenericStatement
+              "command! -nargs=+ -complete=customlist,ferret#private#backcomplete Back call ferret#private#back(<f-args>)"
+          , GenericStatement
+              "command! -nargs=+ -complete=customlist,ferret#private#blackcomplete Black call ferret#private#black(<f-args>)"
           , GenericStatement
               "command! -nargs=1 Acks call ferret#private#acks(<q-args>)"
           , GenericStatement
@@ -1722,6 +1976,10 @@ Project
           , GenericStatement
               "cabbrev <silent> <expr> cpf ((getcmdtype() == ':' && getcmdpos() == 4) ? 'cpf <bar> normal zz' : 'cpf')"
           , GenericStatement "endif"
+          , LetStatement
+              { letLexpr = "g:FerretFormat"
+              , letValue = "get(g:, 'FerretFormat', '%f:%l:%c:%m')"
+              }
           , LetStatement
               { letLexpr = "&cpoptions " , letValue = "s:cpoptions" }
           , UnletStatement { unletBang = False , unletBody = "s:cpoptions" }
@@ -1784,7 +2042,13 @@ Project
       , Plaintext "listing."
       ]
   , Paragraph
-      [ Code "ag"
+      [ Code "rg"
+      , Whitespace
+      , Plaintext "(ripgrep)"
+      , Whitespace
+      , Plaintext "then"
+      , Whitespace
+      , Code "ag"
       , Whitespace
       , Plaintext "(The"
       , Whitespace
@@ -1812,9 +2076,9 @@ Project
       , Whitespace
       , Plaintext "because"
       , Whitespace
-      , Plaintext "it"
+      , Plaintext "they"
       , Whitespace
-      , Plaintext "is"
+      , Plaintext "are"
       , Whitespace
       , Plaintext "faster,"
       , Whitespace
@@ -1825,19 +2089,78 @@ Project
       , Plaintext "to"
       , Whitespace
       , Code "ack"
+      , Plaintext "/"
+      , Code "ack-grep"
+      , Whitespace
+      , Plaintext "as"
+      , Whitespace
+      , Plaintext "needed."
+      ]
+  , Paragraph
+      [ Plaintext "On"
+      , Whitespace
+      , Plaintext "newer"
+      , Whitespace
+      , Plaintext "versions"
+      , Whitespace
+      , Plaintext "of"
+      , Whitespace
+      , Plaintext "Vim"
+      , Whitespace
+      , Plaintext "(version"
+      , Whitespace
+      , Plaintext "8"
       , Whitespace
       , Plaintext "and"
       , Whitespace
-      , Plaintext "then"
+      , Plaintext "above),"
       , Whitespace
-      , Code "grep"
+      , Plaintext "the"
       , Whitespace
-      , Plaintext "as"
+      , Plaintext "search"
       , Whitespace
-      , Plaintext "needed."
+      , Plaintext "process"
+      , Whitespace
+      , Plaintext "runs"
+      , Whitespace
+      , Plaintext "asynchronously"
+      , Whitespace
+      , Plaintext "in"
+      , Whitespace
+      , Plaintext "the"
+      , Whitespace
+      , Plaintext "background"
+      , Whitespace
+      , Plaintext "and"
+      , Whitespace
+      , Plaintext "does"
+      , Whitespace
+      , Plaintext "not"
+      , Whitespace
+      , Plaintext "block"
+      , Whitespace
+      , Plaintext "the"
+      , Whitespace
+      , Plaintext "UI."
       ]
   , Paragraph
-      [ Plaintext "If"
+      [ Plaintext "On"
+      , Whitespace
+      , Plaintext "older"
+      , Whitespace
+      , Plaintext "Vim"
+      , Whitespace
+      , Plaintext "versions"
+      , Whitespace
+      , Plaintext "(prior"
+      , Whitespace
+      , Plaintext "to"
+      , Whitespace
+      , Plaintext "version"
+      , Whitespace
+      , Plaintext "8),"
+      , Whitespace
+      , Plaintext "if"
       , Whitespace
       , Plaintext "dispatch.vim"
       , Whitespace
@@ -1882,7 +2205,32 @@ Project
       , Link ":cexpr"
       , Plaintext "."
       , Whitespace
-      , Plaintext "Asynchronous"
+      , Plaintext "The"
+      , Whitespace
+      , Link "g:FerretDispatch"
+      , Whitespace
+      , Plaintext "option"
+      , Whitespace
+      , Plaintext "can"
+      , Whitespace
+      , Plaintext "be"
+      , Whitespace
+      , Plaintext "used"
+      , Whitespace
+      , Plaintext "to"
+      , Whitespace
+      , Plaintext "prevent"
+      , Whitespace
+      , Plaintext "the"
+      , Whitespace
+      , Plaintext "use"
+      , Whitespace
+      , Plaintext "of"
+      , Whitespace
+      , Plaintext "dispatch.vim."
+      ]
+  , Paragraph
+      [ Plaintext "Asynchronous"
       , Whitespace
       , Plaintext "searches"
       , Whitespace
@@ -1917,30 +2265,6 @@ Project
       , Plaintext "single"
       , Whitespace
       , Plaintext "threaded."
-      , Whitespace
-      , Plaintext "The"
-      , Whitespace
-      , Link "g:FerretDispatch"
-      , Whitespace
-      , Plaintext "option"
-      , Whitespace
-      , Plaintext "can"
-      , Whitespace
-      , Plaintext "be"
-      , Whitespace
-      , Plaintext "used"
-      , Whitespace
-      , Plaintext "to"
-      , Whitespace
-      , Plaintext "prevent"
-      , Whitespace
-      , Plaintext "the"
-      , Whitespace
-      , Plaintext "use"
-      , Whitespace
-      , Plaintext "of"
-      , Whitespace
-      , Plaintext "dispatch.vim."
       ]
   , Paragraph
       [ Plaintext "The"
@@ -2176,83 +2500,326 @@ Project
       , Whitespace
       , Plaintext "instead"
       , Whitespace
-      , Plaintext "of"
+      , Plaintext "of"
+      , Whitespace
+      , Plaintext "using"
+      , Whitespace
+      , Plaintext "the"
+      , Whitespace
+      , Link "quickfix"
+      , Whitespace
+      , Plaintext "listing,"
+      , Whitespace
+      , Plaintext "which"
+      , Whitespace
+      , Plaintext "is"
+      , Whitespace
+      , Plaintext "global"
+      , Whitespace
+      , Plaintext "across"
+      , Whitespace
+      , Plaintext "an"
+      , Whitespace
+      , Plaintext "entire"
+      , Whitespace
+      , Plaintext "Vim"
+      , Whitespace
+      , Plaintext "instance,"
+      , Whitespace
+      , Plaintext "it"
+      , Whitespace
+      , Plaintext "uses"
+      , Whitespace
+      , Plaintext "the"
+      , Whitespace
+      , Link "location-list"
+      , Plaintext ","
+      , Whitespace
+      , Plaintext "which"
+      , Whitespace
+      , Plaintext "is"
+      , Whitespace
+      , Plaintext "a"
+      , Whitespace
+      , Plaintext "per-window"
+      , Whitespace
+      , Plaintext "construct."
+      ]
+  , Paragraph
+      [ Plaintext "Note"
+      , Whitespace
+      , Plaintext "that"
+      , Whitespace
+      , Link ":Lack"
+      , Whitespace
+      , Plaintext "always"
+      , Whitespace
+      , Plaintext "runs"
+      , Whitespace
+      , Plaintext "synchronously"
+      , Whitespace
+      , Plaintext "via"
+      , Whitespace
+      , Link ":cexpr"
+      , Plaintext ","
+      , Whitespace
+      , Plaintext "because"
+      , Whitespace
+      , Plaintext "dispatch.vim"
+      , Whitespace
+      , Plaintext "doesn't"
+      , Whitespace
+      , Plaintext "currently"
+      , Whitespace
+      , Plaintext "support"
+      , Whitespace
+      , Plaintext "the"
+      , Whitespace
+      , Link "location-list"
+      , Plaintext "."
+      ]
+  , CommandAnnotation "Back" (Just "{pattern} {options}")
+  , Paragraph
+      [ Plaintext "Like"
+      , Whitespace
+      , Link ":Ack"
+      , Plaintext ","
+      , Whitespace
+      , Plaintext "but"
+      , Whitespace
+      , Plaintext "searches"
+      , Whitespace
+      , Plaintext "only"
+      , Whitespace
+      , Plaintext "listed"
+      , Whitespace
+      , Plaintext "buffers."
+      , Whitespace
+      , Plaintext "Note"
+      , Whitespace
+      , Plaintext "that"
+      , Whitespace
+      , Plaintext "the"
+      , Whitespace
+      , Plaintext "search"
+      , Whitespace
+      , Plaintext "is"
+      , Whitespace
+      , Plaintext "still"
+      , Whitespace
+      , Plaintext "delegated"
+      , Whitespace
+      , Plaintext "to"
+      , Whitespace
+      , Plaintext "the"
+      , Whitespace
+      , Plaintext "underlying"
+      , Whitespace
+      , Link "'grepprg'"
+      , Whitespace
+      , Plaintext "("
+      , Code "rg"
+      , Plaintext ","
+      , Whitespace
+      , Code "ag"
+      , Plaintext ","
+      , Whitespace
+      , Code "ack"
+      , Whitespace
+      , Plaintext "or"
+      , Whitespace
+      , Code "ack-grep"
+      , Plaintext "),"
+      , Whitespace
+      , Plaintext "which"
+      , Whitespace
+      , Plaintext "means"
+      , Whitespace
+      , Plaintext "that"
+      , Whitespace
+      , Plaintext "only"
+      , Whitespace
+      , Plaintext "buffers"
+      , Whitespace
+      , Plaintext "written"
+      , Whitespace
+      , Plaintext "to"
+      , Whitespace
+      , Plaintext "disk"
+      , Whitespace
+      , Plaintext "will"
+      , Whitespace
+      , Plaintext "be"
+      , Whitespace
+      , Plaintext "searched."
+      , Whitespace
+      , Plaintext "If"
+      , Whitespace
+      , Plaintext "no"
+      , Whitespace
+      , Plaintext "buffers"
+      , Whitespace
+      , Plaintext "are"
+      , Whitespace
+      , Plaintext "written"
+      , Whitespace
+      , Plaintext "to"
+      , Whitespace
+      , Plaintext "disk,"
+      , Whitespace
+      , Plaintext "then"
+      , Whitespace
+      , Link ":Back"
+      , Whitespace
+      , Plaintext "behaves"
+      , Whitespace
+      , Plaintext "exactly"
+      , Whitespace
+      , Plaintext "like"
+      , Whitespace
+      , Link ":Ack"
+      , Whitespace
+      , Plaintext "and"
+      , Whitespace
+      , Plaintext "will"
+      , Whitespace
+      , Plaintext "search"
+      , Whitespace
+      , Plaintext "all"
+      , Whitespace
+      , Plaintext "files"
+      , Whitespace
+      , Plaintext "in"
+      , Whitespace
+      , Plaintext "the"
+      , Whitespace
+      , Plaintext "current"
+      , Whitespace
+      , Plaintext "directory."
+      ]
+  , CommandAnnotation "Black" (Just "{pattern} {options}")
+  , Paragraph
+      [ Plaintext "Like"
+      , Whitespace
+      , Link ":Lack"
+      , Plaintext ","
+      , Whitespace
+      , Plaintext "but"
+      , Whitespace
+      , Plaintext "searches"
+      , Whitespace
+      , Plaintext "only"
+      , Whitespace
+      , Plaintext "listed"
+      , Whitespace
+      , Plaintext "buffers."
+      , Whitespace
+      , Plaintext "As"
+      , Whitespace
+      , Plaintext "with"
+      , Whitespace
+      , Link ":Back"
+      , Plaintext ","
+      , Whitespace
+      , Plaintext "the"
+      , Whitespace
+      , Plaintext "search"
+      , Whitespace
+      , Plaintext "is"
+      , Whitespace
+      , Plaintext "still"
+      , Whitespace
+      , Plaintext "delegated"
+      , Whitespace
+      , Plaintext "to"
+      , Whitespace
+      , Plaintext "the"
+      , Whitespace
+      , Plaintext "underlying"
+      , Whitespace
+      , Link "'grepprg'"
+      , Whitespace
+      , Plaintext "("
+      , Code "rg"
+      , Plaintext ","
+      , Whitespace
+      , Code "ag"
+      , Plaintext ","
+      , Whitespace
+      , Code "ack"
       , Whitespace
-      , Plaintext "using"
+      , Plaintext "or"
       , Whitespace
-      , Plaintext "the"
+      , Code "ack-grep"
+      , Plaintext "),"
       , Whitespace
-      , Link "quickfix"
+      , Plaintext "which"
       , Whitespace
-      , Plaintext "listing,"
+      , Plaintext "means"
       , Whitespace
-      , Plaintext "which"
+      , Plaintext "that"
       , Whitespace
-      , Plaintext "is"
+      , Plaintext "only"
       , Whitespace
-      , Plaintext "global"
+      , Plaintext "buffers"
       , Whitespace
-      , Plaintext "across"
+      , Plaintext "written"
       , Whitespace
-      , Plaintext "an"
+      , Plaintext "to"
       , Whitespace
-      , Plaintext "entire"
+      , Plaintext "disk"
       , Whitespace
-      , Plaintext "Vim"
+      , Plaintext "will"
       , Whitespace
-      , Plaintext "instance,"
+      , Plaintext "be"
       , Whitespace
-      , Plaintext "it"
+      , Plaintext "searched."
       , Whitespace
-      , Plaintext "uses"
+      , Plaintext "Likewise,"
       , Whitespace
-      , Plaintext "the"
+      , Plaintext "If"
       , Whitespace
-      , Link "location-list"
-      , Plaintext ","
+      , Plaintext "no"
       , Whitespace
-      , Plaintext "which"
+      , Plaintext "buffers"
       , Whitespace
-      , Plaintext "is"
+      , Plaintext "are"
       , Whitespace
-      , Plaintext "a"
+      , Plaintext "written"
       , Whitespace
-      , Plaintext "per-window"
+      , Plaintext "to"
       , Whitespace
-      , Plaintext "construct."
-      ]
-  , Paragraph
-      [ Plaintext "Note"
+      , Plaintext "disk,"
       , Whitespace
-      , Plaintext "that"
+      , Plaintext "then"
       , Whitespace
-      , Link ":Lack"
+      , Link ":Black"
       , Whitespace
-      , Plaintext "always"
+      , Plaintext "behaves"
       , Whitespace
-      , Plaintext "runs"
+      , Plaintext "exactly"
       , Whitespace
-      , Plaintext "synchronously"
+      , Plaintext "like"
       , Whitespace
-      , Plaintext "via"
+      , Link ":Lack"
       , Whitespace
-      , Link ":cexpr"
-      , Plaintext ","
+      , Plaintext "and"
       , Whitespace
-      , Plaintext "because"
+      , Plaintext "will"
       , Whitespace
-      , Plaintext "dispatch.vim"
+      , Plaintext "search"
       , Whitespace
-      , Plaintext "doesn't"
+      , Plaintext "all"
       , Whitespace
-      , Plaintext "currently"
+      , Plaintext "files"
       , Whitespace
-      , Plaintext "support"
+      , Plaintext "in"
       , Whitespace
       , Plaintext "the"
       , Whitespace
-      , Link "location-list"
-      , Plaintext "."
+      , Plaintext "current"
+      , Whitespace
+      , Plaintext "directory."
       ]
   , CommandAnnotation "Acks" (Just "/{pattern}/{replacement}/")
   , Paragraph
@@ -2401,13 +2968,29 @@ Project
       , Whitespace
       , Plaintext "used"
       , Whitespace
-      , Plaintext "by"
+      , Plaintext "internally"
       , Whitespace
-      , Plaintext "the"
+      , Plaintext "when"
       , Whitespace
-      , Link ":Acks"
+      , Plaintext "running"
       , Whitespace
-      , Plaintext "command"
+      , Plaintext "on"
+      , Whitespace
+      , Plaintext "older"
+      , Whitespace
+      , Plaintext "versions"
+      , Whitespace
+      , Plaintext "of"
+      , Whitespace
+      , Plaintext "Vim"
+      , Whitespace
+      , Plaintext "(prior"
+      , Whitespace
+      , Plaintext "to"
+      , Whitespace
+      , Plaintext "version"
+      , Whitespace
+      , Plaintext "8)"
       , Whitespace
       , Plaintext "but"
       , Whitespace
@@ -3109,6 +3692,144 @@ Project
       , Plaintext "(off):"
       ]
   , Fenced [ "let g:FerretHlsearch=0" ]
+  , OptionAnnotation
+      "g:FerretExecutable" "string" (Just "\"rg,ag,ack,ack-grep\"")
+  , Paragraph
+      [ Plaintext "Ferret"
+      , Whitespace
+      , Plaintext "will"
+      , Whitespace
+      , Plaintext "preferentially"
+      , Whitespace
+      , Plaintext "use"
+      , Whitespace
+      , Code "rg"
+      , Plaintext ","
+      , Whitespace
+      , Code "ag"
+      , Whitespace
+      , Plaintext "and"
+      , Whitespace
+      , Plaintext "finally"
+      , Whitespace
+      , Code "ack"
+      , Plaintext "/"
+      , Code "ack-grep"
+      , Whitespace
+      , Plaintext "(in"
+      , Whitespace
+      , Plaintext "that"
+      , Whitespace
+      , Plaintext "order,"
+      , Whitespace
+      , Plaintext "using"
+      , Whitespace
+      , Plaintext "the"
+      , Whitespace
+      , Plaintext "first"
+      , Whitespace
+      , Plaintext "found"
+      , Whitespace
+      , Plaintext "executable),"
+      , Whitespace
+      , Plaintext "however"
+      , Whitespace
+      , Plaintext "you"
+      , Whitespace
+      , Plaintext "can"
+      , Whitespace
+      , Plaintext "force"
+      , Whitespace
+      , Plaintext "your"
+      , Whitespace
+      , Plaintext "preference"
+      , Whitespace
+      , Plaintext "for"
+      , Whitespace
+      , Plaintext "a"
+      , Whitespace
+      , Plaintext "specific"
+      , Whitespace
+      , Plaintext "tool"
+      , Whitespace
+      , Plaintext "to"
+      , Whitespace
+      , Plaintext "be"
+      , Whitespace
+      , Plaintext "used"
+      , Whitespace
+      , Plaintext "by"
+      , Whitespace
+      , Plaintext "setting"
+      , Whitespace
+      , Plaintext "an"
+      , Whitespace
+      , Plaintext "override"
+      , Whitespace
+      , Plaintext "in"
+      , Whitespace
+      , Plaintext "your"
+      , Whitespace
+      , Link ".vimrc"
+      , Plaintext "."
+      , Whitespace
+      , Plaintext "Valid"
+      , Whitespace
+      , Plaintext "values"
+      , Whitespace
+      , Plaintext "are"
+      , Whitespace
+      , Plaintext "a"
+      , Whitespace
+      , Plaintext "comma-separated"
+      , Whitespace
+      , Plaintext "list"
+      , Whitespace
+      , Plaintext "of"
+      , Whitespace
+      , Plaintext "\"rg\","
+      , Whitespace
+      , Plaintext "\"ag\","
+      , Whitespace
+      , Plaintext "\"ack\""
+      , Whitespace
+      , Plaintext "or"
+      , Whitespace
+      , Plaintext "\"ack-grep\"."
+      , Whitespace
+      , Plaintext "If"
+      , Whitespace
+      , Plaintext "no"
+      , Whitespace
+      , Plaintext "requested"
+      , Whitespace
+      , Plaintext "executable"
+      , Whitespace
+      , Plaintext "exists,"
+      , Whitespace
+      , Plaintext "Ferret"
+      , Whitespace
+      , Plaintext "will"
+      , Whitespace
+      , Plaintext "fall-back"
+      , Whitespace
+      , Plaintext "to"
+      , Whitespace
+      , Plaintext "the"
+      , Whitespace
+      , Plaintext "next"
+      , Whitespace
+      , Plaintext "in"
+      , Whitespace
+      , Plaintext "the"
+      , Whitespace
+      , Plaintext "default"
+      , Whitespace
+      , Plaintext "list."
+      ]
+  , Paragraph [ Plaintext "Example:" ]
+  , Fenced
+      [ "\" Prefer `ag` over `rg`." , "let g:FerretExecutable='ag,rg'" ]
   , OptionAnnotation "g:FerretQFOptions" "boolean" (Just "1")
   , Paragraph
       [ Plaintext "Controls"
@@ -3326,63 +4047,165 @@ Project
   , Paragraph
       [ Plaintext "To"
       , Whitespace
-      , Plaintext "prevent"
+      , Plaintext "prevent"
+      , Whitespace
+      , Plaintext "these"
+      , Whitespace
+      , Plaintext "mappings"
+      , Whitespace
+      , Plaintext "from"
+      , Whitespace
+      , Plaintext "being"
+      , Whitespace
+      , Plaintext "set"
+      , Whitespace
+      , Plaintext "up,"
+      , Whitespace
+      , Plaintext "set"
+      , Whitespace
+      , Plaintext "to"
+      , Whitespace
+      , Plaintext "0:"
+      ]
+  , Fenced [ "let g:FerretQFMap=0" ]
+  , OptionAnnotation "g:FerretLoaded" "any" Nothing
+  , Paragraph
+      [ Plaintext "To"
+      , Whitespace
+      , Plaintext "prevent"
+      , Whitespace
+      , Plaintext "Ferret"
+      , Whitespace
+      , Plaintext "from"
+      , Whitespace
+      , Plaintext "being"
+      , Whitespace
+      , Plaintext "loaded,"
+      , Whitespace
+      , Plaintext "set"
+      , Whitespace
+      , Link "g:FerretLoaded"
+      , Whitespace
+      , Plaintext "to"
+      , Whitespace
+      , Plaintext "any"
+      , Whitespace
+      , Plaintext "value"
+      , Whitespace
+      , Plaintext "in"
+      , Whitespace
+      , Plaintext "your"
+      , Whitespace
+      , Link ".vimrc"
+      , Plaintext "."
+      , Whitespace
+      , Plaintext "For"
+      , Whitespace
+      , Plaintext "example:"
+      ]
+  , Fenced [ "let g:FerretLoaded=1" ]
+  , OptionAnnotation "g:FerretLazyInit" "boolean" (Just "1")
+  , Paragraph
+      [ Plaintext "In"
+      , Whitespace
+      , Plaintext "order"
       , Whitespace
-      , Plaintext "these"
+      , Plaintext "to"
       , Whitespace
-      , Plaintext "mappings"
+      , Plaintext "minimize"
       , Whitespace
-      , Plaintext "from"
+      , Plaintext "impact"
       , Whitespace
-      , Plaintext "being"
+      , Plaintext "on"
       , Whitespace
-      , Plaintext "set"
+      , Plaintext "Vim"
       , Whitespace
-      , Plaintext "up,"
+      , Plaintext "start-up"
       , Whitespace
-      , Plaintext "set"
+      , Plaintext "time"
+      , Whitespace
+      , Plaintext "Ferret"
+      , Whitespace
+      , Plaintext "will"
+      , Whitespace
+      , Plaintext "initialize"
+      , Whitespace
+      , Plaintext "itself"
+      , Whitespace
+      , Plaintext "lazily"
+      , Whitespace
+      , Plaintext "on"
+      , Whitespace
+      , Plaintext "first"
+      , Whitespace
+      , Plaintext "use"
+      , Whitespace
+      , Plaintext "by"
+      , Whitespace
+      , Plaintext "default."
+      , Whitespace
+      , Plaintext "If"
+      , Whitespace
+      , Plaintext "you"
+      , Whitespace
+      , Plaintext "wish"
       , Whitespace
       , Plaintext "to"
       , Whitespace
-      , Plaintext "0:"
-      ]
-  , Fenced [ "let g:FerretQFMap=0" ]
-  , OptionAnnotation "g:FerretLoaded" "any" Nothing
-  , Paragraph
-      [ Plaintext "To"
+      , Plaintext "force"
       , Whitespace
-      , Plaintext "prevent"
+      , Plaintext "immediate"
       , Whitespace
-      , Plaintext "Ferret"
+      , Plaintext "initialization"
       , Whitespace
-      , Plaintext "from"
+      , Plaintext "(for"
       , Whitespace
-      , Plaintext "being"
+      , Plaintext "example,"
       , Whitespace
-      , Plaintext "loaded,"
+      , Plaintext "to"
       , Whitespace
-      , Plaintext "set"
+      , Plaintext "cause"
       , Whitespace
-      , Link "g:FerretLoaded"
+      , Link "'grepprg'"
+      , Whitespace
+      , Plaintext "and"
+      , Whitespace
+      , Link "'grepformat'"
       , Whitespace
       , Plaintext "to"
       , Whitespace
-      , Plaintext "any"
+      , Plaintext "be"
       , Whitespace
-      , Plaintext "value"
+      , Plaintext "set"
+      , Whitespace
+      , Plaintext "as"
+      , Whitespace
+      , Plaintext "soon"
+      , Whitespace
+      , Plaintext "as"
+      , Whitespace
+      , Plaintext "Vim"
+      , Whitespace
+      , Plaintext "launches),"
+      , Whitespace
+      , Plaintext "then"
+      , Whitespace
+      , Plaintext "set"
+      , Whitespace
+      , Link "g:FerretLazyInit"
+      , Whitespace
+      , Plaintext "to"
+      , Whitespace
+      , Plaintext "0"
       , Whitespace
       , Plaintext "in"
       , Whitespace
       , Plaintext "your"
       , Whitespace
       , Link ".vimrc"
-      , Plaintext "."
-      , Whitespace
-      , Plaintext "For"
-      , Whitespace
-      , Plaintext "example:"
+      , Plaintext ":"
       ]
-  , Fenced [ "let g:FerretLoaded=1" ]
+  , Fenced [ "let g:FerrerLazyInit=0" ]
   , OptionAnnotation "g:FerretMap" "boolean" (Just "1")
   , Paragraph
       [ Plaintext "Controls"
@@ -3524,6 +4347,23 @@ Project
       , Plaintext "0:"
       ]
   , Fenced [ "let g:FerretQFCommands=0" ]
+  , OptionAnnotation
+      "g:FerretFormat" "string" (Just "\"%f:%l:%c:%m\"")
+  , Paragraph
+      [ Plaintext "Sets"
+      , Whitespace
+      , Plaintext "the"
+      , Whitespace
+      , Plaintext "'"
+      , Link "grepformat"
+      , Plaintext "'"
+      , Whitespace
+      , Plaintext "used"
+      , Whitespace
+      , Plaintext "by"
+      , Whitespace
+      , Plaintext "Ferret."
+      ]
   , FooterAnnotation
   , HeadingAnnotation "Custom autocommands"
   , LinkTargets [ "FerretWillWrite" , "FerretDidWrite" ]
@@ -3638,6 +4478,9 @@ Project
       , Whitespace
       , Plaintext "setting"
       , Whitespace
+      , Code "rg"
+      , Plaintext ","
+      , Whitespace
       , Code "ag"
       , Plaintext ","
       , Whitespace
@@ -3645,7 +4488,7 @@ Project
       , Whitespace
       , Plaintext "or"
       , Whitespace
-      , Code "grep"
+      , Code "ack-grep"
       , Whitespace
       , Plaintext "as"
       , Whitespace
@@ -4485,11 +5328,17 @@ Project
       , Whitespace
       , Plaintext "prefers"
       , Whitespace
+      , Code "rg"
+      , Whitespace
+      , Plaintext "then"
+      , Whitespace
       , Code "ag"
       , Whitespace
       , Plaintext "over"
       , Whitespace
       , Code "ack"
+      , Plaintext "/"
+      , Code "ack-grep"
       , Whitespace
       , Plaintext "when"
       , Whitespace
@@ -5206,12 +6055,243 @@ Project
       ]
   , List
       [ ListItem [ Plaintext "Daniel" , Whitespace , Plaintext "Silva" ]
+      , ListItem
+          [ Plaintext "Filip" , Whitespace , Plaintext "Szyma\324ski" ]
       , ListItem [ Plaintext "Joe" , Whitespace , Plaintext "Lencioni" ]
       , ListItem
           [ Plaintext "Nelo-Thara" , Whitespace , Plaintext "Wallus" ]
+      , ListItem [ Plaintext "Tom" , Whitespace , Plaintext "Dooner" ]
       , ListItem [ Plaintext "Vaibhav" , Whitespace , Plaintext "Sagar" ]
       ]
   , HeadingAnnotation "History"
+  , SubheadingAnnotation "master (not yet released)"
+  , List
+      [ ListItem
+          [ Plaintext "Added"
+          , Whitespace
+          , Link "g:FerretLazyInit"
+          , Plaintext "."
+          ]
+      ]
+  , SubheadingAnnotation "1.4 (21 January 2017)"
+  , List
+      [ ListItem
+          [ Plaintext "Drop"
+          , Whitespace
+          , Plaintext "broken"
+          , Whitespace
+          , Plaintext "support"
+          , Whitespace
+          , Plaintext "for"
+          , Whitespace
+          , Code "grep"
+          , Plaintext ","
+          , Whitespace
+          , Plaintext "printing"
+          , Whitespace
+          , Plaintext "a"
+          , Whitespace
+          , Plaintext "prompt"
+          , Whitespace
+          , Plaintext "to"
+          , Whitespace
+          , Plaintext "install"
+          , Whitespace
+          , Code "rg"
+          , Plaintext ","
+          , Whitespace
+          , Code "ag"
+          , Plaintext ","
+          , Whitespace
+          , Plaintext "or"
+          , Whitespace
+          , Code "ack"
+          , Plaintext "/"
+          , Code "ack-grep"
+          , Whitespace
+          , Plaintext "instead."
+          ]
+      , ListItem
+          [ Plaintext "If"
+          , Whitespace
+          , Plaintext "an"
+          , Whitespace
+          , Code "ack"
+          , Whitespace
+          , Plaintext "executable"
+          , Whitespace
+          , Plaintext "is"
+          , Whitespace
+          , Plaintext "not"
+          , Whitespace
+          , Plaintext "found,"
+          , Whitespace
+          , Plaintext "search"
+          , Whitespace
+          , Plaintext "for"
+          , Whitespace
+          , Code "ack-grep"
+          , Plaintext ","
+          , Whitespace
+          , Plaintext "which"
+          , Whitespace
+          , Plaintext "is"
+          , Whitespace
+          , Plaintext "the"
+          , Whitespace
+          , Plaintext "name"
+          , Whitespace
+          , Plaintext "used"
+          , Whitespace
+          , Plaintext "on"
+          , Whitespace
+          , Plaintext "Debian-derived"
+          , Whitespace
+          , Plaintext "distros."
+          ]
+      ]
+  , SubheadingAnnotation "1.3 (8 January 2017)"
+  , List
+      [ ListItem
+          [ Plaintext "Reset"
+          , Whitespace
+          , Link "'errorformat'"
+          , Whitespace
+          , Plaintext "before"
+          , Whitespace
+          , Plaintext "each"
+          , Whitespace
+          , Plaintext "search"
+          , Whitespace
+          , Plaintext "(fixes"
+          , Whitespace
+          , Plaintext "issue"
+          , Whitespace
+          , Plaintext "#31)."
+          ]
+      , ListItem
+          [ Plaintext "Added"
+          , Whitespace
+          , Link ":Back"
+          , Whitespace
+          , Plaintext "and"
+          , Whitespace
+          , Link ":Black"
+          , Whitespace
+          , Plaintext "commands,"
+          , Whitespace
+          , Plaintext "analogous"
+          , Whitespace
+          , Plaintext "to"
+          , Whitespace
+          , Link ":Ack"
+          , Whitespace
+          , Plaintext "and"
+          , Whitespace
+          , Link ":Lack"
+          , Whitespace
+          , Plaintext "but"
+          , Whitespace
+          , Plaintext "scoped"
+          , Whitespace
+          , Plaintext "to"
+          , Whitespace
+          , Plaintext "search"
+          , Whitespace
+          , Plaintext "within"
+          , Whitespace
+          , Plaintext "currently"
+          , Whitespace
+          , Plaintext "open"
+          , Whitespace
+          , Plaintext "buffers"
+          , Whitespace
+          , Plaintext "only."
+          ]
+      , ListItem
+          [ Plaintext "Change"
+          , Whitespace
+          , Link ":Acks"
+          , Whitespace
+          , Plaintext "to"
+          , Whitespace
+          , Plaintext "use"
+          , Whitespace
+          , Link ":cfdo"
+          , Whitespace
+          , Plaintext "when"
+          , Whitespace
+          , Plaintext "available"
+          , Whitespace
+          , Plaintext "rather"
+          , Whitespace
+          , Plaintext "than"
+          , Whitespace
+          , Link ":Qargs"
+          , Whitespace
+          , Plaintext "and"
+          , Whitespace
+          , Link ":argdo"
+          , Plaintext ","
+          , Whitespace
+          , Plaintext "to"
+          , Whitespace
+          , Plaintext "avoid"
+          , Whitespace
+          , Plaintext "polluting"
+          , Whitespace
+          , Plaintext "the"
+          , Whitespace
+          , Link "arglist"
+          , Plaintext "."
+          ]
+      , ListItem
+          [ Plaintext "Remove"
+          , Whitespace
+          , Plaintext "superfluous"
+          , Whitespace
+          , Link "QuickFixCmdPost"
+          , Whitespace
+          , Plaintext "autocommands,"
+          , Whitespace
+          , Plaintext "resolving"
+          , Whitespace
+          , Plaintext "clash"
+          , Whitespace
+          , Plaintext "with"
+          , Whitespace
+          , Plaintext "Neomake"
+          , Whitespace
+          , Plaintext "plug-in"
+          , Whitespace
+          , Plaintext "(patch"
+          , Whitespace
+          , Plaintext "from"
+          , Whitespace
+          , Plaintext "Tom"
+          , Whitespace
+          , Plaintext "Dooner,"
+          , Whitespace
+          , Plaintext "#36)."
+          ]
+      , ListItem
+          [ Plaintext "Add"
+          , Whitespace
+          , Plaintext "support"
+          , Whitespace
+          , Plaintext "for"
+          , Whitespace
+          , Plaintext "searching"
+          , Whitespace
+          , Plaintext "with"
+          , Whitespace
+          , Plaintext "ripgrep"
+          , Whitespace
+          , Plaintext "("
+          , Code "rg"
+          , Plaintext ")."
+          ]
+      ]
   , SubheadingAnnotation "1.2a (16 May 2016)"
   , List
       [ ListItem
index da63f961eef4b21d4d647b8687826b763c4d8b45..119f262b3a433a75b9766b3ae1ace34253d6a209 100644 (file)
@@ -12,18 +12,20 @@ Ferret improves Vim's multi-file search in four ways:
 
 ### 1. Powerful multi-file search<a name="ferret-1-powerful-multi-file-search" href="#user-content-ferret-1-powerful-multi-file-search"></a>
 
-Ferret provides an <strong>[`:Ack`](#user-content-ack)</strong> command for searching across multiple files using The Silver Searcher (https://github.com/ggreer/the_silver_searcher), Ack (http://beyondgrep.com/), or Grep (http://www.gnu.org/software/grep/). Support for passing options through to the underlying search command exists, along with the ability to use full regular expression syntax without doing special escaping.
+Ferret provides an <strong>[`:Ack`](#user-content-ack)</strong> command for searching across multiple files using The Silver Searcher (https://github.com/ggreer/the_silver_searcher), or Ack (http://beyondgrep.com/). Support for passing options through to the underlying search command exists, along with the ability to use full regular expression syntax without doing special escaping. On Vim version 8 or higher, searches are performed asynchronously (without blocking the UI).
 
 Shortcut mappings are provided to start an <strong>[`:Ack`](#user-content-ack)</strong> search (<leader>a) or to search for the word currently under the cursor (<leader>s).
 
 Results are normally displayed in the <strong>`quickfix`</strong> window, but Ferret also provides a <strong>[`:Lack`](#user-content-lack)</strong> command that behaves like <strong>[`:Ack`](#user-content-ack)</strong> but uses the <strong>`location-list`</strong> instead, and a <leader>l mapping as a shortcut to <strong>[`:Lack`](#user-content-lack)</strong>.
 
-Finally, Ferret offers integration with dispatch.vim (https://github.com/tpope/vim-dispatch), which enables asynchronous searching despite the fact that Vim itself is single-threaded.
+<strong>[`:Back`](#user-content-back)</strong> and <strong>[`:Black`](#user-content-black)</strong> are analogous to <strong>[`:Ack`](#user-content-ack)</strong> and <strong>[`:Lack`](#user-content-lack)</strong>, but scoped to search within currently open buffers only.
+
+Finally, Ferret offers integration with dispatch.vim (https://github.com/tpope/vim-dispatch), which enables asynchronous searching on older versions of Vim (prior to version 8), despite the fact that Vim itself is single-threaded.
 
 
 ### 2. Streamlined multi-file replace<a name="ferret-2-streamlined-multi-file-replace" href="#user-content-ferret-2-streamlined-multi-file-replace"></a>
 
-The companion to <strong>[`:Ack`](#user-content-ack)</strong> is <strong>[`:Acks`](#user-content-acks)</strong> (mnemonic: "Ack substitute", accessible via shortcut <leader>r), which allows you to run a multi-file replace across all the files placed in the <strong>`quickfix`</strong> window by a previous invocation of <strong>[`:Ack`](#user-content-ack)</strong>.
+The companion to <strong>[`:Ack`](#user-content-ack)</strong> is <strong>[`:Acks`](#user-content-acks)</strong> (mnemonic: "Ack substitute", accessible via shortcut <leader>r), which allows you to run a multi-file replace across all the files placed in the <strong>`quickfix`</strong> window by a previous invocation of <strong>[`:Ack`](#user-content-ack)</strong> (or <strong>[`:Back`](#user-content-back)</strong>).
 
 
 ### 3. Quickfix listing enhancements<a name="ferret-3-quickfix-listing-enhancements" href="#user-content-ferret-3-quickfix-listing-enhancements"></a>
@@ -70,9 +72,13 @@ To generate help tags under Pathogen, you can do so from inside Vim with:
 
 Searches for {pattern} in all the files under the current directory (see <strong>`:pwd`</strong>), unless otherwise overridden via {options}, and displays the results in the <strong>`quickfix`</strong> listing.
 
-`ag` (The Silver Searcher) will be used preferentially if present on the system, because it is faster, falling back to `ack` and then `grep` as needed.
+`rg` (ripgrep) then `ag` (The Silver Searcher) will be used preferentially if present on the system, because they are faster, falling back to `ack`/`ack-grep` as needed.
+
+On newer versions of Vim (version 8 and above), the search process runs asynchronously in the background and does not block the UI.
+
+On older Vim versions (prior to version 8), if dispatch.vim is installed the search process will run asynchronously via the <strong>`:Make`</strong> command, otherwise it will be run synchronously via <strong>`:cexpr`</strong>. The <strong>`g:FerretDispatch`</strong> option can be used to prevent the use of dispatch.vim.
 
-If dispatch.vim is installed the search process will run asynchronously via the <strong>`:Make`</strong> command, otherwise it will be run synchronously via <strong>`:cexpr`</strong>. Asynchronous searches are preferred because they do not block, despite the fact that Vim itself is single threaded. The <strong>`g:FerretDispatch`</strong> option can be used to prevent the use of dispatch.vim.
+Asynchronous searches are preferred because they do not block, despite the fact that Vim itself is single threaded.
 
 The {pattern} is passed through as-is to the underlying search program, and no escaping is required other than preceding spaces by a single backslash. For example, to search for "\bfoo[0-9]{2} bar\b" (ie. using `ag`'s Perl-style regular expression syntax), you could do:
 
@@ -96,6 +102,18 @@ Just like <strong>[`:Ack`](#user-content-ack)</strong>, but instead of using the
 
 Note that <strong>[`:Lack`](#user-content-lack)</strong> always runs synchronously via <strong>`:cexpr`</strong>, because dispatch.vim doesn't currently support the <strong>`location-list`</strong>.
 
+<p align="right"><a name="back" href="#user-content-back"><code>:Back</code></a></p>
+
+### `:Back {pattern} {options}`<a name="ferret-back-pattern-options" href="#user-content-ferret-back-pattern-options"></a>
+
+Like <strong>[`:Ack`](#user-content-ack)</strong>, but searches only listed buffers. Note that the search is still delegated to the underlying <strong>`'grepprg'`</strong> (`rg`, `ag`, `ack` or `ack-grep`), which means that only buffers written to disk will be searched. If no buffers are written to disk, then <strong>[`:Back`](#user-content-back)</strong> behaves exactly like <strong>[`:Ack`](#user-content-ack)</strong> and will search all files in the current directory.
+
+<p align="right"><a name="black" href="#user-content-black"><code>:Black</code></a></p>
+
+### `:Black {pattern} {options}`<a name="ferret-black-pattern-options" href="#user-content-ferret-black-pattern-options"></a>
+
+Like <strong>[`:Lack`](#user-content-lack)</strong>, but searches only listed buffers. As with <strong>[`:Back`](#user-content-back)</strong>, the search is still delegated to the underlying <strong>`'grepprg'`</strong> (`rg`, `ag`, `ack` or `ack-grep`), which means that only buffers written to disk will be searched. Likewise, If no buffers are written to disk, then <strong>[`:Black`](#user-content-black)</strong> behaves exactly like <strong>[`:Lack`](#user-content-lack)</strong> and will search all files in the current directory.
+
 <p align="right"><a name="acks" href="#user-content-acks"><code>:Acks</code></a></p>
 
 ### `:Acks /{pattern}/{replacement}/`<a name="ferret-acks-patternreplacement" href="#user-content-ferret-acks-patternreplacement"></a>
@@ -113,7 +131,7 @@ A typical sequence consists of an <strong>[`:Ack`](#user-content-ack)</strong> i
 
 ### `:Qargs`<a name="ferret-qargs" href="#user-content-ferret-qargs"></a>
 
-This is a utility function that is used by the <strong>[`:Acks`](#user-content-acks)</strong> command but is also generally useful enough to warrant being exposed publicly.
+This is a utility function that is used internally when running on older versions of Vim (prior to version 8) but is also generally useful enough to warrant being exposed publicly.
 
 It takes the files currently in the <strong>`quickfix`</strong> listing and sets them as <strong>`:args`</strong> so that they can be operated on en masse via the <strong>`:argdo`</strong> command.
 
@@ -201,6 +219,19 @@ Controls whether Ferret should attempt to highlight the search pattern when runn
 let g:FerretHlsearch=0
 ```
 
+<p align="right"><a name="gferretexecutable" href="#user-content-gferretexecutable"><code>g:FerretExecutable</code></a></p>
+
+### `g:FerretExecutable` (string, default: "rg,ag,ack,ack-grep")<a name="ferret-gferretexecutable-string-default-rgagackack-grep" href="#user-content-ferret-gferretexecutable-string-default-rgagackack-grep"></a>
+
+Ferret will preferentially use `rg`, `ag` and finally `ack`/`ack-grep` (in that order, using the first found executable), however you can force your preference for a specific tool to be used by setting an override in your <strong>`.vimrc`</strong>. Valid values are a comma-separated list of "rg", "ag", "ack" or "ack-grep". If no requested executable exists, Ferret will fall-back to the next in the default list.
+
+Example:
+
+```
+" Prefer `ag` over `rg`.
+let g:FerretExecutable='ag,rg'
+```
+
 <p align="right"><a name="gferretqfoptions" href="#user-content-gferretqfoptions"><code>g:FerretQFOptions</code></a></p>
 
 ### `g:FerretQFOptions` (boolean, default: 1)<a name="ferret-gferretqfoptions-boolean-default-1" href="#user-content-ferret-gferretqfoptions-boolean-default-1"></a>
@@ -241,6 +272,16 @@ To prevent Ferret from being loaded, set <strong>`g:FerretLoaded`</strong> to an
 let g:FerretLoaded=1
 ```
 
+<p align="right"><a name="gferretlazyinit" href="#user-content-gferretlazyinit"><code>g:FerretLazyInit</code></a></p>
+
+### `g:FerretLazyInit` (boolean, default: 1)<a name="ferret-gferretlazyinit-boolean-default-1" href="#user-content-ferret-gferretlazyinit-boolean-default-1"></a>
+
+In order to minimize impact on Vim start-up time Ferret will initialize itself lazily on first use by default. If you wish to force immediate initialization (for example, to cause <strong>`'grepprg'`</strong> and <strong>`'grepformat'`</strong> to be set as soon as Vim launches), then set <strong>`g:FerretLazyInit`</strong> to 0 in your <strong>`.vimrc`</strong>:
+
+```
+let g:FerrerLazyInit=0
+```
+
 <p align="right"><a name="gferretmap" href="#user-content-gferretmap"><code>g:FerretMap</code></a></p>
 
 ### `g:FerretMap` (boolean, default: 1)<a name="ferret-gferretmap-boolean-default-1" href="#user-content-ferret-gferretmap-boolean-default-1"></a>
@@ -261,6 +302,12 @@ Controls whether to set up custom versions of the <strong>`quickfix`</strong> co
 let g:FerretQFCommands=0
 ```
 
+<p align="right"><a name="gferretformat" href="#user-content-gferretformat"><code>g:FerretFormat</code></a></p>
+
+### `g:FerretFormat` (string, default: "%f:%l:%c:%m")<a name="ferret-gferretformat-string-default-flcm" href="#user-content-ferret-gferretformat-string-default-flcm"></a>
+
+Sets the '<strong>`grepformat`</strong>' used by Ferret.
+
 
 ## Custom autocommands<a name="ferret-custom-autocommands" href="#user-content-ferret-custom-autocommands"></a>
 
@@ -282,7 +329,7 @@ autocmd User FerretDidWrite call CustomDidWrite()
 
 ## Overrides<a name="ferret-overrides" href="#user-content-ferret-overrides"></a>
 
-Ferret overrides the 'grepformat' and 'grepprg' settings, preferentially setting `ag`, `ack` or `grep` as the 'grepprg' (in that order) and configuring a suitable 'grepformat'.
+Ferret overrides the 'grepformat' and 'grepprg' settings, preferentially setting `rg`, `ag`, `ack` or `ack-grep` as the 'grepprg' (in that order) and configuring a suitable 'grepformat'.
 
 Additionally, Ferret includes an <strong>`ftplugin`</strong> for the <strong>`quickfix`</strong> listing that adjusts a number of settings to improve the usability of search results.
 
@@ -367,7 +414,7 @@ This approach to escaping is taken in order to make it straightfoward to use pow
 
 Ferret was originally the thinnest of wrappers (7 lines of code in my <strong>`.vimrc`</strong>) around `ack`. The earliest traces of it can be seen in the initial commit to my dotfiles repo in May, 2009 (https://wt.pe/h).
 
-So, even though Ferret has a new name now and actually prefers `ag` over `ack` when available, I prefer to keep the command names intact and benefit from years of accumulated muscle-memory.
+So, even though Ferret has a new name now and actually prefers `rg` then `ag` over `ack`/`ack-grep` when available, I prefer to keep the command names intact and benefit from years of accumulated muscle-memory.
 
 
 ## Related<a name="ferret-related" href="#user-content-ferret-related"></a>
@@ -456,14 +503,36 @@ The idea for vim-dispatch integration was taken from Miles Sterrett's ack.vim pl
 Other contributors that have submitted patches include (in alphabetical order):
 
 - Daniel Silva
+- Filip SzymaDski
 - Joe Lencioni
 - Nelo-Thara Wallus
+- Tom Dooner
 - Vaibhav Sagar
 
 
 ## History<a name="ferret-history" href="#user-content-ferret-history"></a>
 
 
+### master (not yet released)<a name="ferret-master-not-yet-released" href="#user-content-ferret-master-not-yet-released"></a>
+
+- Added <strong>`g:FerretLazyInit`</strong>.
+
+
+### 1.4 (21 January 2017)<a name="ferret-14-21-january-2017" href="#user-content-ferret-14-21-january-2017"></a>
+
+- Drop broken support for `grep`, printing a prompt to install `rg`, `ag`, or `ack`/`ack-grep` instead.
+- If an `ack` executable is not found, search for `ack-grep`, which is the name used on Debian-derived distros.
+
+
+### 1.3 (8 January 2017)<a name="ferret-13-8-january-2017" href="#user-content-ferret-13-8-january-2017"></a>
+
+- Reset <strong>`'errorformat'`</strong> before each search (fixes issue #31).
+- Added <strong>[`:Back`](#user-content-back)</strong> and <strong>[`:Black`](#user-content-black)</strong> commands, analogous to <strong>[`:Ack`](#user-content-ack)</strong> and <strong>[`:Lack`](#user-content-lack)</strong> but scoped to search within currently open buffers only.
+- Change <strong>[`:Acks`](#user-content-acks)</strong> to use <strong>`:cfdo`</strong> when available rather than <strong>[`:Qargs`](#user-content-qargs)</strong> and <strong>`:argdo`</strong>, to avoid polluting the <strong>`arglist`</strong>.
+- Remove superfluous <strong>`QuickFixCmdPost`</strong> autocommands, resolving clash with Neomake plug-in (patch from Tom Dooner, #36).
+- Add support for searching with ripgrep (`rg`).
+
+
 ### 1.2a (16 May 2016)<a name="ferret-12a-16-may-2016" href="#user-content-ferret-12a-16-may-2016"></a>
 
 - Add optional support for running searches asynchronously using Vim's <strong>`+job`</strong> feature (enabled by default in sufficiently recent versions of Vim); see <strong>`g:FerretJob`</strong>, <strong>`:FerretCancelAsync`</strong> and <strong>`:FerretPullAsync`</strong>.
index 6dee12a7443c952053b462b5c91211ca8345adb3..e03a45eb722f1dc67babcfd3d7fad8d864a910d6 100644 (file)
@@ -31,11 +31,11 @@ Ferret improves Vim's multi-file search in four ways:
 1. Powerful multi-file search ~
 
 Ferret provides an |:Ack| command for searching across multiple files using
-The Silver Searcher (https://github.com/ggreer/the_silver_searcher), Ack
-(http://beyondgrep.com/), or Grep (http://www.gnu.org/software/grep/).
-Support for passing options through to the underlying search command exists,
-along with the ability to use full regular expression syntax without doing
-special escaping.
+The Silver Searcher (https://github.com/ggreer/the_silver_searcher), or Ack
+(http://beyondgrep.com/). Support for passing options through to the
+underlying search command exists, along with the ability to use full regular
+expression syntax without doing special escaping. On Vim version 8 or
+higher, searches are performed asynchronously (without blocking the UI).
 
 Shortcut mappings are provided to start an |:Ack| search (<leader>a) or to
 search for the word currently under the cursor (<leader>s).
@@ -44,15 +44,20 @@ Results are normally displayed in the |quickfix| window, but Ferret also
 provides a |:Lack| command that behaves like |:Ack| but uses the |location-list|
 instead, and a <leader>l mapping as a shortcut to |:Lack|.
 
+|:Back| and |:Black| are analogous to |:Ack| and |:Lack|, but scoped to search
+within currently open buffers only.
+
 Finally, Ferret offers integration with dispatch.vim
 (https://github.com/tpope/vim-dispatch), which enables asynchronous
-searching despite the fact that Vim itself is single-threaded.
+searching on older versions of Vim (prior to version 8), despite the fact
+that Vim itself is single-threaded.
 
 2. Streamlined multi-file replace ~
 
 The companion to |:Ack| is |:Acks| (mnemonic: "Ack substitute", accessible via
 shortcut <leader>r), which allows you to run a multi-file replace across all
-the files placed in the |quickfix| window by a previous invocation of |:Ack|.
+the files placed in the |quickfix| window by a previous invocation of |:Ack| (or
+|:Back|).
 
 3. Quickfix listing enhancements ~
 
@@ -100,15 +105,21 @@ Searches for {pattern} in all the files under the current directory (see
 |:pwd|), unless otherwise overridden via {options}, and displays the results
 in the |quickfix| listing.
 
-`ag` (The Silver Searcher) will be used preferentially if present on the
-system, because it is faster, falling back to `ack` and then `grep` as needed.
+`rg` (ripgrep) then `ag` (The Silver Searcher) will be used preferentially if
+present on the system, because they are faster, falling back to `ack`/`ack-grep`
+as needed.
 
-If dispatch.vim is installed the search process will run asynchronously via
-the |:Make| command, otherwise it will be run synchronously via |:cexpr|.
-Asynchronous searches are preferred because they do not block, despite the
-fact that Vim itself is single threaded. The |g:FerretDispatch| option can be
+On newer versions of Vim (version 8 and above), the search process runs
+asynchronously in the background and does not block the UI.
+
+On older Vim versions (prior to version 8), if dispatch.vim is installed the
+search process will run asynchronously via the |:Make| command, otherwise it
+will be run synchronously via |:cexpr|. The |g:FerretDispatch| option can be
 used to prevent the use of dispatch.vim.
 
+Asynchronous searches are preferred because they do not block, despite the
+fact that Vim itself is single threaded.
+
 The {pattern} is passed through as-is to the underlying search program, and
 no escaping is required other than preceding spaces by a single backslash.
 For example, to search for "\bfoo[0-9]{2} bar\b" (ie. using `ag`'s Perl-style
@@ -136,6 +147,22 @@ per-window construct.
 Note that |:Lack| always runs synchronously via |:cexpr|, because dispatch.vim
 doesn't currently support the |location-list|.
 
+:Back {pattern} {options}                                                *:Back*
+
+Like |:Ack|, but searches only listed buffers. Note that the search is still
+delegated to the underlying |'grepprg'| (`rg`, `ag`, `ack` or `ack-grep`), which means
+that only buffers written to disk will be searched. If no buffers are
+written to disk, then |:Back| behaves exactly like |:Ack| and will search all
+files in the current directory.
+
+:Black {pattern} {options}                                              *:Black*
+
+Like |:Lack|, but searches only listed buffers. As with |:Back|, the search is
+still delegated to the underlying |'grepprg'| (`rg`, `ag`, `ack` or `ack-grep`), which
+means that only buffers written to disk will be searched. Likewise, If no
+buffers are written to disk, then |:Black| behaves exactly like |:Lack| and will
+search all files in the current directory.
+
 :Acks /{pattern}/{replacement}/                                          *:Acks*
 
 Takes all of the files currently in the |quickfix| listing and performs a
@@ -152,8 +179,9 @@ directory:
 <
 :Qargs                                                                  *:Qargs*
 
-This is a utility function that is used by the |:Acks| command but is also
-generally useful enough to warrant being exposed publicly.
+This is a utility function that is used internally when running on older
+versions of Vim (prior to version 8) but is also generally useful enough to
+warrant being exposed publicly.
 
 It takes the files currently in the |quickfix| listing and sets them as |:args|
 so that they can be operated on en masse via the |:argdo| command.
@@ -241,6 +269,22 @@ running |:Ack| or |:Lack|. If left unset, Ferret will respect the current
     let g:FerretHlsearch=0
 <
 
+                                                            *g:FerretExecutable*
+|g:FerretExecutable|                      string (default: "rg,ag,ack,ack-grep")
+
+Ferret will preferentially use `rg`, `ag` and finally `ack`/`ack-grep` (in that
+order, using the first found executable), however you can force your
+preference for a specific tool to be used by setting an override in your
+|.vimrc|. Valid values are a comma-separated list of "rg", "ag", "ack" or
+"ack-grep". If no requested executable exists, Ferret will fall-back to the
+next in the default list.
+
+Example:
+>
+    " Prefer `ag` over `rg`.
+    let g:FerretExecutable='ag,rg'
+<
+
                                                              *g:FerretQFOptions*
 |g:FerretQFOptions|                                         boolean (default: 1)
 
@@ -281,6 +325,17 @@ To prevent Ferret from being loaded, set |g:FerretLoaded| to any value in your
     let g:FerretLoaded=1
 <
 
+                                                              *g:FerretLazyInit*
+|g:FerretLazyInit|                                          boolean (default: 1)
+
+In order to minimize impact on Vim start-up time Ferret will initialize
+itself lazily on first use by default. If you wish to force immediate
+initialization (for example, to cause |'grepprg'| and |'grepformat'| to be set
+as soon as Vim launches), then set |g:FerretLazyInit| to 0 in your |.vimrc|:
+>
+    let g:FerrerLazyInit=0
+<
+
                                                                    *g:FerretMap*
 |g:FerretMap|                                               boolean (default: 1)
 
@@ -301,6 +356,12 @@ set to 0:
 >
     let g:FerretQFCommands=0
 <
+
+                                                                *g:FerretFormat*
+|g:FerretFormat|                                 string (default: "%f:%l:%c:%m")
+
+Sets the '|grepformat|' used by Ferret.
+
 CUSTOM AUTOCOMMANDS                                 *ferret-custom-autocommands*
 
 
@@ -323,8 +384,8 @@ you might do:
 OVERRIDES                                                     *ferret-overrides*
 
 Ferret overrides the 'grepformat' and 'grepprg' settings, preferentially
-setting `ag`, `ack` or `grep` as the 'grepprg' (in that order) and configuring a
-suitable 'grepformat'.
+setting `rg`, `ag`, `ack` or `ack-grep` as the 'grepprg' (in that order) and
+configuring a suitable 'grepformat'.
 
 Additionally, Ferret includes an |ftplugin| for the |quickfix| listing that
 adjusts a number of settings to improve the usability of search results.
@@ -421,9 +482,9 @@ Ferret was originally the thinnest of wrappers (7 lines of code in my
 |.vimrc|) around `ack`. The earliest traces of it can be seen in the initial
 commit to my dotfiles repo in May, 2009 (https://wt.pe/h).
 
-So, even though Ferret has a new name now and actually prefers `ag` over `ack`
-when available, I prefer to keep the command names intact and benefit from
-years of accumulated muscle-memory.
+So, even though Ferret has a new name now and actually prefers `rg` then `ag`
+over `ack`/`ack-grep` when available, I prefer to keep the command names intact
+and benefit from years of accumulated muscle-memory.
 
 RELATED                                                         *ferret-related*
 
@@ -515,12 +576,36 @@ Other contributors that have submitted patches include (in alphabetical
 order):
 
 - Daniel Silva
+- Filip SzymaDski
 - Joe Lencioni
 - Nelo-Thara Wallus
+- Tom Dooner
 - Vaibhav Sagar
 
 HISTORY                                                         *ferret-history*
 
+master (not yet released) ~
+
+- Added |g:FerretLazyInit|.
+
+1.4 (21 January 2017) ~
+
+- Drop broken support for `grep`, printing a prompt to install `rg`, `ag`, or
+  `ack`/`ack-grep` instead.
+- If an `ack` executable is not found, search for `ack-grep`, which is the name
+  used on Debian-derived distros.
+
+1.3 (8 January 2017) ~
+
+- Reset |'errorformat'| before each search (fixes issue #31).
+- Added |:Back| and |:Black| commands, analogous to |:Ack| and |:Lack| but scoped to
+  search within currently open buffers only.
+- Change |:Acks| to use |:cfdo| when available rather than |:Qargs| and |:argdo|, to
+  avoid polluting the |arglist|.
+- Remove superfluous |QuickFixCmdPost| autocommands, resolving clash with
+  Neomake plug-in (patch from Tom Dooner, #36).
+- Add support for searching with ripgrep (`rg`).
+
 1.2a (16 May 2016) ~
 
 - Add optional support for running searches asynchronously using Vim's |+job|