Update Ferret fixture files
authorGreg Hurrell <greg@hurrell.net>
Thu, 4 May 2017 16:13:54 +0000 (09:13 -0700)
committerGreg Hurrell <greg@hurrell.net>
Thu, 4 May 2017 16:13:54 +0000 (09:13 -0700)
tests/fixtures/integration/ferret/golden/ast.golden
tests/fixtures/integration/ferret/golden/markdown.golden
tests/fixtures/integration/ferret/golden/plaintext.golden
tests/fixtures/integration/ferret/input/autoload/ferret/private.vim
tests/fixtures/integration/ferret/input/autoload/ferret/private/async.vim
tests/fixtures/integration/ferret/input/plugin/ferret.vim

index 16e79c7b5ee4497167dcffaa2e3e2de2d9e0fa6b..6ca26b6abfd8c8a207719deefd583cb7a2e18e5a 100644 (file)
@@ -951,7 +951,8 @@ Project
               , functionArguments = ArgumentList []
               , functionAttributes = []
               , functionBody =
-                  [ LetStatement
+                  [ Empty
+                  , LetStatement
                       { letLexpr = "l:async" , letValue = "get(g:, 'FerretJob', 1)" }
                   , GenericStatement "return l:async && has('patch-7-4-1829')"
                   ]
@@ -1096,7 +1097,8 @@ Project
           , FunctionDeclaration
               { functionBang = True
               , functionName = "ferret#private#ack"
-              , functionArguments = ArgumentList [ Argument "..." ]
+              , functionArguments =
+                  ArgumentList [ Argument "bang" , Argument "..." ]
               , functionAttributes = [ "abort" ]
               , functionBody =
                   [ LetStatement
@@ -1111,7 +1113,8 @@ Project
                   , GenericStatement "return"
                   , GenericStatement "endif"
                   , GenericStatement "if ferret#private#async()"
-                  , GenericStatement "call ferret#private#async#search(l:command, 1)"
+                  , GenericStatement
+                      "call ferret#private#async#search(l:command, 1, a:bang)"
                   , GenericStatement "elseif ferret#private#dispatch()"
                   , GenericStatement "call ferret#private#dispatch#search(l:command)"
                   , GenericStatement "else"
@@ -1141,21 +1144,23 @@ Project
           , FunctionDeclaration
               { functionBang = True
               , functionName = "ferret#private#back"
-              , functionArguments = ArgumentList [ Argument "..." ]
+              , functionArguments =
+                  ArgumentList [ Argument "bang" , Argument "..." ]
               , functionAttributes = [ "abort" ]
               , functionBody =
                   [ GenericStatement
-                      "call call('ferret#private#ack', a:000 + ferret#private#buflist())"
+                      "call call('ferret#private#ack', a:bang, a:000 + ferret#private#buflist())"
                   ]
               }
           , FunctionDeclaration
               { functionBang = True
               , functionName = "ferret#private#black"
-              , functionArguments = ArgumentList [ Argument "..." ]
+              , functionArguments =
+                  ArgumentList [ Argument "bang" , Argument "..." ]
               , functionAttributes = [ "abort" ]
               , functionBody =
                   [ GenericStatement
-                      "call call('ferret#private#lack', a:000 + ferret#private#buflist())"
+                      "call call('ferret#private#lack', a:bang, a:000 + ferret#private#buflist())"
                   ]
               }
           , FunctionDeclaration
@@ -1171,7 +1176,8 @@ Project
           , FunctionDeclaration
               { functionBang = True
               , functionName = "ferret#private#lack"
-              , functionArguments = ArgumentList [ Argument "..." ]
+              , functionArguments =
+                  ArgumentList [ Argument "bang" , Argument "..." ]
               , functionAttributes = [ "abort" ]
               , functionBody =
                   [ LetStatement
@@ -1186,7 +1192,8 @@ Project
                   , GenericStatement "return"
                   , GenericStatement "endif"
                   , GenericStatement "if ferret#private#async()"
-                  , GenericStatement "call ferret#private#async#search(l:command, 0)"
+                  , GenericStatement
+                      "call ferret#private#async#search(l:command, 0, a:bang)"
                   , GenericStatement "else"
                   , GenericStatement
                       "call ferret#private#vanilla#search(l:command, 0)"
@@ -1489,15 +1496,15 @@ Project
                   , GenericStatement "endif"
                   , GenericStatement "if executable('ag')"
                   , LetStatement
-                      { letLexpr = "s:ag_help" , letValue = "system('ag --help')" }
-                  , GenericStatement "if match(s:ag_help, '--vimgrep') != -1"
+                      { letLexpr = "l:ag_help" , letValue = "system('ag --help')" }
+                  , GenericStatement "if match(l: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"
+                  , GenericStatement "if match(l:ag_help, '--width') != -1"
                   , LetStatement
                       { letLexpr = "s:executables['ag']."
                       , letValue = "' --width 4096'"
@@ -1576,7 +1583,8 @@ Project
               { functionBang = True
               , functionName = "ferret#private#async#search"
               , functionArguments =
-                  ArgumentList [ Argument "command" , Argument "ack" ]
+                  ArgumentList
+                    [ Argument "command" , Argument "ack" , Argument "bang" ]
               , functionAttributes = [ "abort" ]
               , functionBody =
                   [ GenericStatement "call ferret#private#async#cancel()"
@@ -1602,7 +1610,7 @@ Project
                   , LetStatement
                       { letLexpr = "s:jobs[l:channel_id]" , letValue = "{" }
                   , GenericStatement
-                      "\\ 'channel_id': l:channel_id, 'job': l:job, 'errors': [], 'output': [], 'pending_error': '', 'pending_output': '', 'pending_error_length': 0, 'pending_output_length': 0, 'ack': a:ack, 'window': win_getid() }"
+                      "\\ 'channel_id': l:channel_id, 'job': l:job, 'errors': [], 'output': [], 'pending_error': '', 'pending_output': '', 'pending_error_length': 0, 'pending_output_length': 0, 'result_count': 0, 'ack': a:ack, 'bang': a:bang, 'window': win_getid() }"
                   ]
               }
           , LetStatement
@@ -1653,6 +1661,10 @@ Project
                   , GenericStatement "endif"
                   ]
               }
+          , LetStatement
+              { letLexpr = "s:limit"
+              , letValue = "max([1, +get(g:, 'FerretMaxResults', 100000)]) - 1"
+              }
           , FunctionDeclaration
               { functionBang = True
               , functionName = "ferret#private#async#out_cb"
@@ -1665,6 +1677,11 @@ Project
                       , letValue = "s:info_from_channel(a:channel)"
                       }
                   , GenericStatement "if type(l:info) == 4"
+                  , GenericStatement
+                      "if !l:info.bang && l:info.result_count > s:limit"
+                  , GenericStatement "call s:MaxResultsExceeded(l:info)"
+                  , GenericStatement "return"
+                  , GenericStatement "endif"
                   , LetStatement
                       { letLexpr = "l:lines" , letValue = "split(a:msg, '\\n', 1)" }
                   , LetStatement { letLexpr = "l:count" , letValue = "len(l:lines)" }
@@ -1686,6 +1703,14 @@ Project
                       { letLexpr = "l:info.pending_output" , letValue = "''" }
                   , LetStatement
                       { letLexpr = "l:info.pending_output_length" , letValue = "0" }
+                  , GenericStatement "if !l:info.bang"
+                  , LetStatement
+                      { letLexpr = "l:info.result_count+" , letValue = "1" }
+                  , GenericStatement "if l:info.result_count > s:limit"
+                  , GenericStatement "call s:MaxResultsExceeded(l:info)"
+                  , GenericStatement "break"
+                  , GenericStatement "endif"
+                  , GenericStatement "endif"
                   , GenericStatement
                       "elseif l:info.pending_output_length < s:max_line_length"
                   , LetStatement
@@ -1758,6 +1783,22 @@ Project
                   , GenericStatement "endif"
                   ]
               }
+          , FunctionDeclaration
+              { functionBang = True
+              , functionName = "s:MaxResultsExceeded"
+              , functionArguments = ArgumentList [ Argument "info" ]
+              , functionAttributes = []
+              , functionBody =
+                  [ GenericStatement
+                      "call ferret#private#shared#finalize_search(a:info.output, a:info.ack)"
+                  , GenericStatement "call job_stop(a:info.job)"
+                  , GenericStatement "call remove(s:jobs, a:info.channel_id)"
+                  , GenericStatement
+                      "call ferret#private#autocmd('FerretAsyncFinish')"
+                  , GenericStatement
+                      "call ferret#private#error( 'Maximum result count exceeded. ' . 'Either increase g:FerretMaxResults or ' . 're-run the search with :Ack!, :Lack! etc.' )"
+                  ]
+              }
           , FunctionDeclaration
               { functionBang = True
               , functionName = "ferret#private#async#debug"
@@ -1921,13 +1962,13 @@ Project
           , GenericStatement "call ferret#private#init()"
           , GenericStatement "endif"
           , GenericStatement
-              "command! -nargs=+ -complete=customlist,ferret#private#ackcomplete Ack call ferret#private#ack(<f-args>)"
+              "command! -bang -nargs=+ -complete=customlist,ferret#private#ackcomplete Ack call ferret#private#ack(<bang>0, <f-args>)"
           , GenericStatement
-              "command! -nargs=+ -complete=customlist,ferret#private#lackcomplete Lack call ferret#private#lack(<f-args>)"
+              "command! -bang -nargs=+ -complete=customlist,ferret#private#lackcomplete Lack call ferret#private#lack(<bang>0, <f-args>)"
           , GenericStatement
-              "command! -nargs=+ -complete=customlist,ferret#private#backcomplete Back call ferret#private#back(<f-args>)"
+              "command! -bang -nargs=+ -complete=customlist,ferret#private#backcomplete Back call ferret#private#back(<bang>0, <f-args>)"
           , GenericStatement
-              "command! -nargs=+ -complete=customlist,ferret#private#blackcomplete Black call ferret#private#black(<f-args>)"
+              "command! -bang -nargs=+ -complete=customlist,ferret#private#blackcomplete Black call ferret#private#black(<bang>0, <f-args>)"
           , GenericStatement
               "command! -nargs=1 Acks call ferret#private#acks(<q-args>)"
           , GenericStatement
@@ -2487,6 +2528,34 @@ Project
       , Whitespace
       , Plaintext "cursor."
       ]
+  , CommandAnnotation "Ack!" (Just "{pattern} {options}")
+  , Paragraph
+      [ Plaintext "Like"
+      , Whitespace
+      , Link ":Ack"
+      , Plaintext ","
+      , Whitespace
+      , Plaintext "but"
+      , Whitespace
+      , Plaintext "returns"
+      , Whitespace
+      , Plaintext "all"
+      , Whitespace
+      , Plaintext "results"
+      , Whitespace
+      , Plaintext "irrespective"
+      , Whitespace
+      , Plaintext "of"
+      , Whitespace
+      , Plaintext "the"
+      , Whitespace
+      , Plaintext "value"
+      , Whitespace
+      , Plaintext "of"
+      , Whitespace
+      , Link "g:FerretMaxResults"
+      , Plaintext "."
+      ]
   , CommandAnnotation "Lack" (Just "{pattern} {options}")
   , Paragraph
       [ Plaintext "Just"
@@ -2578,6 +2647,34 @@ Project
       , Link "location-list"
       , Plaintext "."
       ]
+  , CommandAnnotation "Lack!" (Just "{pattern} {options}")
+  , Paragraph
+      [ Plaintext "Like"
+      , Whitespace
+      , Link ":Lack"
+      , Plaintext ","
+      , Whitespace
+      , Plaintext "but"
+      , Whitespace
+      , Plaintext "returns"
+      , Whitespace
+      , Plaintext "all"
+      , Whitespace
+      , Plaintext "results"
+      , Whitespace
+      , Plaintext "irrespective"
+      , Whitespace
+      , Plaintext "of"
+      , Whitespace
+      , Plaintext "the"
+      , Whitespace
+      , Plaintext "value"
+      , Whitespace
+      , Plaintext "of"
+      , Whitespace
+      , Link "g:FerretMaxResults"
+      , Plaintext "."
+      ]
   , CommandAnnotation "Back" (Just "{pattern} {options}")
   , Paragraph
       [ Plaintext "Like"
@@ -2697,6 +2794,34 @@ Project
       , Whitespace
       , Plaintext "directory."
       ]
+  , CommandAnnotation "Back!" (Just "{pattern} {options}")
+  , Paragraph
+      [ Plaintext "Like"
+      , Whitespace
+      , Link ":Back"
+      , Plaintext ","
+      , Whitespace
+      , Plaintext "but"
+      , Whitespace
+      , Plaintext "returns"
+      , Whitespace
+      , Plaintext "all"
+      , Whitespace
+      , Plaintext "results"
+      , Whitespace
+      , Plaintext "irrespective"
+      , Whitespace
+      , Plaintext "of"
+      , Whitespace
+      , Plaintext "the"
+      , Whitespace
+      , Plaintext "value"
+      , Whitespace
+      , Plaintext "of"
+      , Whitespace
+      , Link "g:FerretMaxResults"
+      , Plaintext "."
+      ]
   , CommandAnnotation "Black" (Just "{pattern} {options}")
   , Paragraph
       [ Plaintext "Like"
@@ -2821,6 +2946,34 @@ Project
       , Whitespace
       , Plaintext "directory."
       ]
+  , CommandAnnotation "Black!" (Just "{pattern} {options}")
+  , Paragraph
+      [ Plaintext "Like"
+      , Whitespace
+      , Link ":Black"
+      , Plaintext ","
+      , Whitespace
+      , Plaintext "but"
+      , Whitespace
+      , Plaintext "returns"
+      , Whitespace
+      , Plaintext "all"
+      , Whitespace
+      , Plaintext "results"
+      , Whitespace
+      , Plaintext "irrespective"
+      , Whitespace
+      , Plaintext "of"
+      , Whitespace
+      , Plaintext "the"
+      , Whitespace
+      , Plaintext "value"
+      , Whitespace
+      , Plaintext "of"
+      , Whitespace
+      , Link "g:FerretMaxResults"
+      , Plaintext "."
+      ]
   , CommandAnnotation "Acks" (Just "/{pattern}/{replacement}/")
   , Paragraph
       [ Plaintext "Takes"
@@ -3604,6 +3757,144 @@ Project
       , Plaintext "0:"
       ]
   , Fenced [ "let g:FerretDispatch=0" ]
+  , Paragraph
+      [ Plaintext "Note"
+      , Whitespace
+      , Plaintext "that"
+      , Whitespace
+      , Plaintext "on"
+      , Whitespace
+      , Plaintext "sufficiently"
+      , Whitespace
+      , Plaintext "recent"
+      , Whitespace
+      , Plaintext "versions"
+      , Whitespace
+      , Plaintext "of"
+      , Whitespace
+      , Plaintext "Vim"
+      , Whitespace
+      , Plaintext "with"
+      , Whitespace
+      , Link "+job"
+      , Whitespace
+      , Plaintext "support,"
+      , Whitespace
+      , Plaintext "Ferret"
+      , Whitespace
+      , Plaintext "will"
+      , Whitespace
+      , Plaintext "first"
+      , Whitespace
+      , Plaintext "try"
+      , Whitespace
+      , Plaintext "to"
+      , Whitespace
+      , Plaintext "use"
+      , Whitespace
+      , Link "+job"
+      , Plaintext ","
+      , Whitespace
+      , Plaintext "falling"
+      , Whitespace
+      , Plaintext "back"
+      , Whitespace
+      , Plaintext "to"
+      , Whitespace
+      , Plaintext "vim-dispatch"
+      , Whitespace
+      , Plaintext "and"
+      , Whitespace
+      , Plaintext "consulting"
+      , Whitespace
+      , Link "g:FerretDispatch"
+      , Whitespace
+      , Plaintext "only"
+      , Whitespace
+      , Plaintext "if"
+      , Whitespace
+      , Link "g:FerretJob"
+      , Whitespace
+      , Plaintext "is"
+      , Whitespace
+      , Plaintext "set"
+      , Whitespace
+      , Plaintext "to"
+      , Whitespace
+      , Plaintext "0."
+      ]
+  , OptionAnnotation "g:FerretJob" "boolean" (Just "1")
+  , Paragraph
+      [ Plaintext "Controls"
+      , Whitespace
+      , Plaintext "whether"
+      , Whitespace
+      , Plaintext "to"
+      , Whitespace
+      , Plaintext "use"
+      , Whitespace
+      , Plaintext "Vim's"
+      , Whitespace
+      , Link "+job"
+      , Whitespace
+      , Plaintext "feature,"
+      , Whitespace
+      , Plaintext "when"
+      , Whitespace
+      , Plaintext "available,"
+      , Whitespace
+      , Plaintext "to"
+      , Whitespace
+      , Plaintext "run"
+      , Whitespace
+      , Plaintext "searches"
+      , Whitespace
+      , Plaintext "asynchronously."
+      , Whitespace
+      , Plaintext "To"
+      , Whitespace
+      , Plaintext "prevent"
+      , Whitespace
+      , Link "+job"
+      , Whitespace
+      , Plaintext "from"
+      , Whitespace
+      , Plaintext "being"
+      , Whitespace
+      , Plaintext "used,"
+      , Whitespace
+      , Plaintext "set"
+      , Whitespace
+      , Plaintext "to"
+      , Whitespace
+      , Plaintext "0,"
+      , Whitespace
+      , Plaintext "in"
+      , Whitespace
+      , Plaintext "which"
+      , Whitespace
+      , Plaintext "case"
+      , Whitespace
+      , Plaintext "Ferret"
+      , Whitespace
+      , Plaintext "will"
+      , Whitespace
+      , Plaintext "fall"
+      , Whitespace
+      , Plaintext "back"
+      , Whitespace
+      , Plaintext "to"
+      , Whitespace
+      , Plaintext "vim-dispatch"
+      , Whitespace
+      , Plaintext "(see"
+      , Whitespace
+      , Plaintext "also:"
+      , Whitespace
+      , Link "g:FerretDispatch"
+      , Plaintext "):"
+      ]
+  , Fenced [ "let g:FerretJob=0" ]
   , OptionAnnotation "g:FerretHlsearch" "boolean" Nothing
   , Paragraph
       [ Plaintext "Controls"
@@ -3830,15 +4121,251 @@ Project
   , Paragraph [ Plaintext "Example:" ]
   , Fenced
       [ "\" Prefer `ag` over `rg`." , "let g:FerretExecutable='ag,rg'" ]
-  , OptionAnnotation "g:FerretQFOptions" "boolean" (Just "1")
+  , OptionAnnotation "g:FerretMaxResults" "number" (Just "100000")
   , Paragraph
       [ Plaintext "Controls"
       , Whitespace
-      , Plaintext "whether"
+      , Plaintext "the"
       , Whitespace
-      , Plaintext "to"
+      , Plaintext "maximum"
       , Whitespace
-      , Plaintext "set"
+      , Plaintext "number"
+      , Whitespace
+      , Plaintext "of"
+      , Whitespace
+      , Plaintext "results"
+      , Whitespace
+      , Plaintext "Ferret"
+      , Whitespace
+      , Plaintext "will"
+      , Whitespace
+      , Plaintext "attempt"
+      , Whitespace
+      , Plaintext "to"
+      , Whitespace
+      , Plaintext "gather"
+      , Whitespace
+      , Plaintext "before"
+      , Whitespace
+      , Plaintext "displaying"
+      , Whitespace
+      , Plaintext "the"
+      , Whitespace
+      , Plaintext "results."
+      , Whitespace
+      , Plaintext "Note"
+      , Whitespace
+      , Plaintext "that"
+      , Whitespace
+      , Plaintext "this"
+      , Whitespace
+      , Plaintext "only"
+      , Whitespace
+      , Plaintext "applies"
+      , Whitespace
+      , Plaintext "when"
+      , Whitespace
+      , Plaintext "searching"
+      , Whitespace
+      , Plaintext "asynchronously;"
+      , Whitespace
+      , Plaintext "that"
+      , Whitespace
+      , Plaintext "is,"
+      , Whitespace
+      , Plaintext "on"
+      , Whitespace
+      , Plaintext "recent"
+      , Whitespace
+      , Plaintext "versions"
+      , Whitespace
+      , Plaintext "of"
+      , Whitespace
+      , Plaintext "Vim"
+      , Whitespace
+      , Plaintext "with"
+      , Whitespace
+      , Link "+job"
+      , Whitespace
+      , Plaintext "support"
+      , Whitespace
+      , Plaintext "and"
+      , Whitespace
+      , Plaintext "when"
+      , Whitespace
+      , Link "g:FerretJob"
+      , Whitespace
+      , Plaintext "is"
+      , Whitespace
+      , Plaintext "not"
+      , Whitespace
+      , Plaintext "set"
+      , Whitespace
+      , Plaintext "to"
+      , Whitespace
+      , Plaintext "0."
+      ]
+  , Paragraph
+      [ Plaintext "The"
+      , Whitespace
+      , Plaintext "intent"
+      , Whitespace
+      , Plaintext "of"
+      , Whitespace
+      , Plaintext "this"
+      , Whitespace
+      , Plaintext "option"
+      , Whitespace
+      , Plaintext "is"
+      , Whitespace
+      , Plaintext "to"
+      , Whitespace
+      , Plaintext "prevent"
+      , Whitespace
+      , Plaintext "runaway"
+      , Whitespace
+      , Plaintext "search"
+      , Whitespace
+      , Plaintext "processes"
+      , Whitespace
+      , Plaintext "that"
+      , Whitespace
+      , Plaintext "produce"
+      , Whitespace
+      , Plaintext "huge"
+      , Whitespace
+      , Plaintext "volumes"
+      , Whitespace
+      , Plaintext "of"
+      , Whitespace
+      , Plaintext "output"
+      , Whitespace
+      , Plaintext "(for"
+      , Whitespace
+      , Plaintext "example,"
+      , Whitespace
+      , Plaintext "searching"
+      , Whitespace
+      , Plaintext "for"
+      , Whitespace
+      , Plaintext "a"
+      , Whitespace
+      , Plaintext "common"
+      , Whitespace
+      , Plaintext "string"
+      , Whitespace
+      , Plaintext "like"
+      , Whitespace
+      , Plaintext "\"test\""
+      , Whitespace
+      , Plaintext "inside"
+      , Whitespace
+      , Plaintext "a"
+      , Whitespace
+      , Link "$HOME"
+      , Whitespace
+      , Plaintext "directory"
+      , Whitespace
+      , Plaintext "containing"
+      , Whitespace
+      , Plaintext "millions"
+      , Whitespace
+      , Plaintext "of"
+      , Whitespace
+      , Plaintext "files)"
+      , Whitespace
+      , Plaintext "from"
+      , Whitespace
+      , Plaintext "locking"
+      , Whitespace
+      , Plaintext "up"
+      , Whitespace
+      , Plaintext "Vim."
+      ]
+  , Paragraph
+      [ Plaintext "In"
+      , Whitespace
+      , Plaintext "the"
+      , Whitespace
+      , Plaintext "event"
+      , Whitespace
+      , Plaintext "that"
+      , Whitespace
+      , Plaintext "Ferret"
+      , Whitespace
+      , Plaintext "aborts"
+      , Whitespace
+      , Plaintext "a"
+      , Whitespace
+      , Plaintext "search"
+      , Whitespace
+      , Plaintext "that"
+      , Whitespace
+      , Plaintext "has"
+      , Whitespace
+      , Plaintext "hit"
+      , Whitespace
+      , Plaintext "the"
+      , Whitespace
+      , Link "g:FerretMaxResults"
+      , Whitespace
+      , Plaintext "limit,"
+      , Whitespace
+      , Plaintext "a"
+      , Whitespace
+      , Plaintext "message"
+      , Whitespace
+      , Plaintext "will"
+      , Whitespace
+      , Plaintext "be"
+      , Whitespace
+      , Plaintext "printed"
+      , Whitespace
+      , Plaintext "prompting"
+      , Whitespace
+      , Plaintext "users"
+      , Whitespace
+      , Plaintext "to"
+      , Whitespace
+      , Plaintext "run"
+      , Whitespace
+      , Plaintext "the"
+      , Whitespace
+      , Plaintext "search"
+      , Whitespace
+      , Plaintext "again"
+      , Whitespace
+      , Plaintext "with"
+      , Whitespace
+      , Link ":Ack!"
+      , Whitespace
+      , Plaintext "or"
+      , Whitespace
+      , Link ":Lack!"
+      , Whitespace
+      , Plaintext "if"
+      , Whitespace
+      , Plaintext "they"
+      , Whitespace
+      , Plaintext "want"
+      , Whitespace
+      , Plaintext "to"
+      , Whitespace
+      , Plaintext "bypass"
+      , Whitespace
+      , Plaintext "the"
+      , Whitespace
+      , Plaintext "limit."
+      ]
+  , OptionAnnotation "g:FerretQFOptions" "boolean" (Just "1")
+  , Paragraph
+      [ Plaintext "Controls"
+      , Whitespace
+      , Plaintext "whether"
+      , Whitespace
+      , Plaintext "to"
+      , Whitespace
+      , Plaintext "set"
       , Whitespace
       , Plaintext "up"
       , Whitespace
@@ -6067,11 +6594,114 @@ Project
   , SubheadingAnnotation "master (not yet released)"
   , List
       [ ListItem
+          [ Plaintext "Improvements"
+          , Whitespace
+          , Plaintext "to"
+          , Whitespace
+          , Plaintext "the"
+          , Whitespace
+          , Plaintext "handling"
+          , Whitespace
+          , Plaintext "of"
+          , Whitespace
+          , Plaintext "very"
+          , Whitespace
+          , Plaintext "large"
+          , Whitespace
+          , Plaintext "result"
+          , Whitespace
+          , Plaintext "sets"
+          , Whitespace
+          , Plaintext "(due"
+          , Whitespace
+          , Plaintext "to"
+          , Whitespace
+          , Plaintext "wide"
+          , Whitespace
+          , Plaintext "lines"
+          , Whitespace
+          , Plaintext "or"
+          , Whitespace
+          , Plaintext "many"
+          , Whitespace
+          , Plaintext "results)."
+          ]
+      , ListItem
           [ Plaintext "Added"
           , Whitespace
           , Link "g:FerretLazyInit"
           , Plaintext "."
           ]
+      , ListItem
+          [ Plaintext "Added"
+          , Whitespace
+          , Plaintext "missing"
+          , Whitespace
+          , Plaintext "documentation"
+          , Whitespace
+          , Plaintext "for"
+          , Whitespace
+          , Link "g:FerretJob"
+          , Plaintext "."
+          ]
+      , ListItem
+          [ Plaintext "Added"
+          , Whitespace
+          , Link "g:FerretMaxResults"
+          , Plaintext "."
+          ]
+      , ListItem
+          [ Plaintext "Added"
+          , Whitespace
+          , Plaintext "feature-detection"
+          , Whitespace
+          , Plaintext "for"
+          , Whitespace
+          , Code "rg"
+          , Whitespace
+          , Plaintext "and"
+          , Whitespace
+          , Code "ag"
+          , Plaintext ","
+          , Whitespace
+          , Plaintext "allowing"
+          , Whitespace
+          , Plaintext "Ferret"
+          , Whitespace
+          , Plaintext "to"
+          , Whitespace
+          , Plaintext "gracefully"
+          , Whitespace
+          , Plaintext "work"
+          , Whitespace
+          , Plaintext "with"
+          , Whitespace
+          , Plaintext "older"
+          , Whitespace
+          , Plaintext "versions"
+          , Whitespace
+          , Plaintext "of"
+          , Whitespace
+          , Plaintext "those"
+          , Whitespace
+          , Plaintext "tools"
+          , Whitespace
+          , Plaintext "that"
+          , Whitespace
+          , Plaintext "do"
+          , Whitespace
+          , Plaintext "not"
+          , Whitespace
+          , Plaintext "support"
+          , Whitespace
+          , Plaintext "all"
+          , Whitespace
+          , Plaintext "desired"
+          , Whitespace
+          , Plaintext "command-line"
+          , Whitespace
+          , Plaintext "switches."
+          ]
       ]
   , SubheadingAnnotation "1.4 (21 January 2017)"
   , List
index 42b6c4e8069d95717b05cdd4eca80f3c1593ed9c..9d2e91e091b5daa0263e8fc15437fc8aebf54c3b 100644 (file)
@@ -94,6 +94,12 @@ Likewise, {options} are passed through. In this example, we pass the `-w` option
 
 As a convenience <leader>a is set-up (<strong>[`<Plug>(FerretAck)`](#user-content-plugferretack)</strong>) as a shortcut to enter <strong>`Cmdline-mode`</strong> with `:Ack` inserted on the <strong>`Cmdline`</strong>. Likewise <leader>s (<strong>[`<Plug>(FerretAckWord)`](#user-content-plugferretackword)</strong>) is a shortcut for running <strong>[`:Ack`](#user-content-ack)</strong> with the word currently under the cursor.
 
+<p align="right"><a name="ack" href="#user-content-ack"><code>:Ack!</code></a></p>
+
+### `:Ack! {pattern} {options}`<a name="ferret-ack-pattern-options" href="#user-content-ferret-ack-pattern-options"></a>
+
+Like <strong>[`:Ack`](#user-content-ack)</strong>, but returns all results irrespective of the value of <strong>`g:FerretMaxResults`</strong>.
+
 <p align="right"><a name="lack" href="#user-content-lack"><code>:Lack</code></a></p>
 
 ### `:Lack {pattern} {options}`<a name="ferret-lack-pattern-options" href="#user-content-ferret-lack-pattern-options"></a>
@@ -102,18 +108,36 @@ 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="lack" href="#user-content-lack"><code>:Lack!</code></a></p>
+
+### `:Lack! {pattern} {options}`<a name="ferret-lack-pattern-options" href="#user-content-ferret-lack-pattern-options"></a>
+
+Like <strong>[`:Lack`](#user-content-lack)</strong>, but returns all results irrespective of the value of <strong>`g:FerretMaxResults`</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="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>[`:Back`](#user-content-back)</strong>, but returns all results irrespective of the value of <strong>`g:FerretMaxResults`</strong>.
+
 <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="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>[`:Black`](#user-content-black)</strong>, but returns all results irrespective of the value of <strong>`g:FerretMaxResults`</strong>.
+
 <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>
@@ -209,6 +233,18 @@ Controls whether to use vim-dispatch (and specifically, <strong>`:Make`</strong>
 let g:FerretDispatch=0
 ```
 
+Note that on sufficiently recent versions of Vim with <strong>`+job`</strong> support, Ferret will first try to use <strong>`+job`</strong>, falling back to vim-dispatch and consulting <strong>`g:FerretDispatch`</strong> only if <strong>`g:FerretJob`</strong> is set to 0.
+
+<p align="right"><a name="gferretjob" href="#user-content-gferretjob"><code>g:FerretJob</code></a></p>
+
+### `g:FerretJob` (boolean, default: 1)<a name="ferret-gferretjob-boolean-default-1" href="#user-content-ferret-gferretjob-boolean-default-1"></a>
+
+Controls whether to use Vim's <strong>`+job`</strong> feature, when available, to run searches asynchronously. To prevent <strong>`+job`</strong> from being used, set to 0, in which case Ferret will fall back to vim-dispatch (see also: <strong>`g:FerretDispatch`</strong>):
+
+```
+let g:FerretJob=0
+```
+
 <p align="right"><a name="gferrethlsearch" href="#user-content-gferrethlsearch"><code>g:FerretHlsearch</code></a></p>
 
 ### `g:FerretHlsearch` (boolean, default: none)<a name="ferret-gferrethlsearch-boolean-default-none" href="#user-content-ferret-gferrethlsearch-boolean-default-none"></a>
@@ -232,6 +268,16 @@ Example:
 let g:FerretExecutable='ag,rg'
 ```
 
+<p align="right"><a name="gferretmaxresults" href="#user-content-gferretmaxresults"><code>g:FerretMaxResults</code></a></p>
+
+### `g:FerretMaxResults` (number, default: 100000)<a name="ferret-gferretmaxresults-number-default-100000" href="#user-content-ferret-gferretmaxresults-number-default-100000"></a>
+
+Controls the maximum number of results Ferret will attempt to gather before displaying the results. Note that this only applies when searching asynchronously; that is, on recent versions of Vim with <strong>`+job`</strong> support and when <strong>`g:FerretJob`</strong> is not set to 0.
+
+The intent of this option is to prevent runaway search processes that produce huge volumes of output (for example, searching for a common string like "test" inside a <strong>`$HOME`</strong> directory containing millions of files) from locking up Vim.
+
+In the event that Ferret aborts a search that has hit the <strong>`g:FerretMaxResults`</strong> limit, a message will be printed prompting users to run the search again with <strong>[`:Ack!`](#user-content-ack)</strong> or <strong>[`:Lack!`](#user-content-lack)</strong> if they want to bypass the limit.
+
 <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>
@@ -515,7 +561,11 @@ Other contributors that have submitted patches include (in alphabetical order):
 
 ### master (not yet released)<a name="ferret-master-not-yet-released" href="#user-content-ferret-master-not-yet-released"></a>
 
+- Improvements to the handling of very large result sets (due to wide lines or many results).
 - Added <strong>`g:FerretLazyInit`</strong>.
+- Added missing documentation for <strong>`g:FerretJob`</strong>.
+- Added <strong>`g:FerretMaxResults`</strong>.
+- Added feature-detection for `rg` and `ag`, allowing Ferret to gracefully work with older versions of those tools that do not support all desired command-line switches.
 
 
 ### 1.4 (21 January 2017)<a name="ferret-14-21-january-2017" href="#user-content-ferret-14-21-january-2017"></a>
index 62f3bb8ac25b1347e073eb46e923f7f013a8e798..93ddf2bf46e94d058612abfc20f755249703c9e7 100644 (file)
@@ -138,6 +138,11 @@ enter |Cmdline-mode| with `:Ack` inserted on the |Cmdline|. Likewise <leader>s
 (|<Plug>(FerretAckWord)|) is a shortcut for running |:Ack| with the word
 currently under the cursor.
 
+:Ack! {pattern} {options}                                                *:Ack!*
+
+Like |:Ack|, but returns all results irrespective of the value of
+|g:FerretMaxResults|.
+
 :Lack {pattern} {options}                                                *:Lack*
 
 Just like |:Ack|, but instead of using the |quickfix| listing, which is global
@@ -147,6 +152,11 @@ per-window construct.
 Note that |:Lack| always runs synchronously via |:cexpr|, because dispatch.vim
 doesn't currently support the |location-list|.
 
+:Lack! {pattern} {options}                                              *:Lack!*
+
+Like |:Lack|, but returns all results irrespective of the value of
+|g:FerretMaxResults|.
+
 :Back {pattern} {options}                                                *:Back*
 
 Like |:Ack|, but searches only listed buffers. Note that the search is still
@@ -155,6 +165,11 @@ 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.
 
+:Back! {pattern} {options}                                              *:Back!*
+
+Like |:Back|, but returns all results irrespective of the value of
+|g:FerretMaxResults|.
+
 :Black {pattern} {options}                                              *:Black*
 
 Like |:Lack|, but searches only listed buffers. As with |:Back|, the search is
@@ -163,6 +178,11 @@ 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.
 
+:Black! {pattern} {options}                                            *:Black!*
+
+Like |:Black|, but returns all results irrespective of the value of
+|g:FerretMaxResults|.
+
 :Acks /{pattern}/{replacement}/                                          *:Acks*
 
 Takes all of the files currently in the |quickfix| listing and performs a
@@ -257,6 +277,20 @@ used, set to 0:
 >
     let g:FerretDispatch=0
 <
+Note that on sufficiently recent versions of Vim with |+job| support, Ferret
+will first try to use |+job|, falling back to vim-dispatch and consulting
+|g:FerretDispatch| only if |g:FerretJob| is set to 0.
+
+
+                                                                   *g:FerretJob*
+|g:FerretJob|                                               boolean (default: 1)
+
+Controls whether to use Vim's |+job| feature, when available, to run searches
+asynchronously. To prevent |+job| from being used, set to 0, in which case
+Ferret will fall back to vim-dispatch (see also: |g:FerretDispatch|):
+>
+    let g:FerretJob=0
+<
 
                                                               *g:FerretHlsearch*
 |g:FerretHlsearch|                                       boolean (default: none)
@@ -285,6 +319,24 @@ Example:
     let g:FerretExecutable='ag,rg'
 <
 
+                                                            *g:FerretMaxResults*
+|g:FerretMaxResults|                                    number (default: 100000)
+
+Controls the maximum number of results Ferret will attempt to gather before
+displaying the results. Note that this only applies when searching
+asynchronously; that is, on recent versions of Vim with |+job| support and
+when |g:FerretJob| is not set to 0.
+
+The intent of this option is to prevent runaway search processes that
+produce huge volumes of output (for example, searching for a common string
+like "test" inside a |$HOME| directory containing millions of files) from
+locking up Vim.
+
+In the event that Ferret aborts a search that has hit the |g:FerretMaxResults|
+limit, a message will be printed prompting users to run the search again
+with |:Ack!| or |:Lack!| if they want to bypass the limit.
+
+
                                                              *g:FerretQFOptions*
 |g:FerretQFOptions|                                         boolean (default: 1)
 
@@ -586,7 +638,14 @@ HISTORY                                                         *ferret-history*
 
 master (not yet released) ~
 
+- Improvements to the handling of very large result sets (due to wide lines
+  or many results).
 - Added |g:FerretLazyInit|.
+- Added missing documentation for |g:FerretJob|.
+- Added |g:FerretMaxResults|.
+- Added feature-detection for `rg` and `ag`, allowing Ferret to gracefully work
+  with older versions of those tools that do not support all desired
+  command-line switches.
 
 1.4 (21 January 2017) ~
 
index 66d50fb00fa0277381f5bf4f278a1a551fc6634e..28a7988d9f1b82d30d96b70eb61ea60e8aae3019 100644 (file)
@@ -32,12 +32,28 @@ function! ferret#private#dispatch() abort
   " ```
   " let g:FerretDispatch=0
   " ```
+  "
+  " Note that on sufficiently recent versions of Vim with |+job| support, Ferret
+  " will first try to use |+job|, falling back to vim-dispatch and consulting
+  " |g:FerretDispatch| only if |g:FerretJob| is set to 0.
+  "
   let l:dispatch=get(g:, 'FerretDispatch', 1)
   return l:dispatch && exists(':Make') == 2
 endfunction
 
 " Returns 1 if we can use Vim's built-in async primitives.
 function! ferret#private#async()
+  ""
+  " @option g:FerretJob boolean 1
+  "
+  " Controls whether to use Vim's |+job| feature, when available, to run
+  " searches asynchronously. To prevent |+job| from being used, set to 0, in
+  " which case Ferret will fall back to vim-dispatch (see also:
+  " |g:FerretDispatch|):
+  "
+  " ```
+  " let g:FerretJob=0
+  " ```
   let l:async=get(g:, 'FerretJob', 1)
 
   " Nothing special about 1829; it's just the version I am testing with as I
@@ -174,7 +190,7 @@ function! ferret#private#post(type) abort
   endif
 endfunction
 
-function! ferret#private#ack(...) abort
+function! ferret#private#ack(bang, ...) abort
   let l:command=s:parse(a:000)
   call ferret#private#hlsearch()
 
@@ -185,7 +201,7 @@ function! ferret#private#ack(...) abort
   endif
 
   if ferret#private#async()
-    call ferret#private#async#search(l:command, 1)
+    call ferret#private#async#search(l:command, 1, a:bang)
   elseif ferret#private#dispatch()
     call ferret#private#dispatch#search(l:command)
   else
@@ -199,12 +215,12 @@ function! ferret#private#buflist() abort
   return l:bufpaths
 endfunction
 
-function! ferret#private#back(...) abort
-  call call('ferret#private#ack', a:000 + ferret#private#buflist())
+function! ferret#private#back(bang, ...) abort
+  call call('ferret#private#ack', a:bang, a:000 + ferret#private#buflist())
 endfunction
 
-function! ferret#private#black(...) abort
-  call call('ferret#private#lack', a:000 + ferret#private#buflist())
+function! ferret#private#black(bang, ...) abort
+  call call('ferret#private#lack', a:bang, a:000 + ferret#private#buflist())
 endfunction
 
 function! ferret#private#installprompt() abort
@@ -213,7 +229,7 @@ function! ferret#private#installprompt() abort
         \ )
 endfunction
 
-function! ferret#private#lack(...) abort
+function! ferret#private#lack(bang, ...) abort
   let l:command=s:parse(a:000)
   call ferret#private#hlsearch()
 
@@ -224,7 +240,7 @@ function! ferret#private#lack(...) abort
   endif
 
   if ferret#private#async()
-    call ferret#private#async#search(l:command, 0)
+    call ferret#private#async#search(l:command, 0, a:bang)
   else
     call ferret#private#vanilla#search(l:command, 0)
   endif
@@ -570,13 +586,13 @@ function! ferret#private#init() abort
   endif
 
   if executable('ag')
-    let s:ag_help=system('ag --help')
-    if match(s:ag_help, '--vimgrep') != -1
+    let l:ag_help=system('ag --help')
+    if match(l:ag_help, '--vimgrep') != -1
       let s:executables['ag'].=' --vimgrep'
     else
       let s:executables['ag'].=' --column'
     endif
-    if match(s:ag_help, '--width') != -1
+    if match(l:ag_help, '--width') != -1
       let s:executables['ag'].=' --width 4096'
     endif
   endif
index b2be96de9019d224674c075d5b94f521bfae883e..97a513ba72ac4e62c8c07df0c3ccd5c490ff7385 100644 (file)
@@ -10,7 +10,7 @@ function! s:info_from_channel(channel)
   endif
 endfunction
 
-function! ferret#private#async#search(command, ack) abort
+function! ferret#private#async#search(command, ack, bang) abort
   call ferret#private#async#cancel()
   call ferret#private#autocmd('FerretAsyncStart')
   let l:command_and_args=extend(split(ferret#private#executable()), a:command)
@@ -33,7 +33,9 @@ function! ferret#private#async#search(command, ack) abort
         \   'pending_output': '',
         \   'pending_error_length': 0,
         \   'pending_output_length': 0,
+        \   'result_count': 0,
         \   'ack': a:ack,
+        \   'bang': a:bang,
         \   'window': win_getid()
         \ }
 endfunction
@@ -69,9 +71,31 @@ function! ferret#private#async#err_cb(channel, msg)
   endif
 endfunction
 
+""
+" @option g:FerretMaxResults number 100000
+"
+" Controls the maximum number of results Ferret will attempt to gather before
+" displaying the results. Note that this only applies when searching
+" asynchronously; that is, on recent versions of Vim with |+job| support and
+" when |g:FerretJob| is not set to 0.
+"
+" The intent of this option is to prevent runaway search processes that produce
+" huge volumes of output (for example, searching for a common string like "test"
+" inside a |$HOME| directory containing millions of files) from locking up Vim.
+"
+" In the event that Ferret aborts a search that has hit the |g:FerretMaxResults|
+" limit, a message will be printed prompting users to run the search again
+" with |:Ack!| or |:Lack!| if they want to bypass the limit.
+"
+let s:limit=max([1, +get(g:, 'FerretMaxResults', 100000)]) - 1
+
 function! ferret#private#async#out_cb(channel, msg)
   let l:info=s:info_from_channel(a:channel)
   if type(l:info) == 4
+    if !l:info.bang && l:info.result_count > s:limit
+      call s:MaxResultsExceeded(l:info)
+      return
+    endif
     let l:lines=split(a:msg, '\n', 1)
     let l:count=len(l:lines)
     for l:i in range(l:count)
@@ -89,6 +113,13 @@ function! ferret#private#async#out_cb(channel, msg)
         endif
         let l:info.pending_output=''
         let l:info.pending_output_length=0
+        if !l:info.bang
+          let l:info.result_count+=1
+          if l:info.result_count > s:limit
+            call s:MaxResultsExceeded(l:info)
+            break
+          endif
+        endif
       elseif l:info.pending_output_length < s:max_line_length
         let l:info.pending_output.=l:line
         let l:info.pending_output_length+=strlen(l:line)
@@ -134,6 +165,19 @@ function! ferret#private#async#cancel() abort
   endif
 endfunction
 
+" Stop a single job as a result of hitting g:FerretMaxResults.
+function! s:MaxResultsExceeded(info)
+  call ferret#private#shared#finalize_search(a:info.output, a:info.ack)
+  call job_stop(a:info.job)
+  call remove(s:jobs, a:info.channel_id)
+  call ferret#private#autocmd('FerretAsyncFinish')
+  call ferret#private#error(
+        \   'Maximum result count exceeded. ' .
+        \   'Either increase g:FerretMaxResults or ' .
+        \   're-run the search with :Ack!, :Lack! etc.'
+        \ )
+endfunction
+
 function! ferret#private#async#debug() abort
   return s:jobs
 endfunction
index 8254bcf6cb47d10398f5245b90b47aa2a433b1d5..32261908ad873092c68739fb8e706e82ce3ef279 100644 (file)
 "
 " ## master (not yet released)
 "
+" - Improvements to the handling of very large result sets (due to wide lines or
+"   many results).
 " - Added |g:FerretLazyInit|.
+" - Added missing documentation for |g:FerretJob|.
+" - Added |g:FerretMaxResults|.
+" - Added feature-detection for `rg` and `ag`, allowing Ferret to gracefully
+"   work with older versions of those tools that do not support all desired
+"   command-line switches.
 "
 " ## 1.4 (21 January 2017)
 "
@@ -506,7 +513,13 @@ endif
 " enter |Cmdline-mode| with `:Ack` inserted on the |Cmdline|. Likewise <leader>s
 " (|<Plug>(FerretAckWord)|) is a shortcut for running |:Ack| with the word
 " currently under the cursor.
-command! -nargs=+ -complete=customlist,ferret#private#ackcomplete Ack call ferret#private#ack(<f-args>)
+"
+" @command :Ack! {pattern} {options}
+"
+" Like |:Ack|, but returns all results irrespective of the value of
+" |g:FerretMaxResults|.
+"
+command! -bang -nargs=+ -complete=customlist,ferret#private#ackcomplete Ack call ferret#private#ack(<bang>0, <f-args>)
 
 ""
 " @command :Lack {pattern} {options}
@@ -517,7 +530,13 @@ command! -nargs=+ -complete=customlist,ferret#private#ackcomplete Ack call ferre
 "
 " Note that |:Lack| always runs synchronously via |:cexpr|, because dispatch.vim
 " doesn't currently support the |location-list|.
-command! -nargs=+ -complete=customlist,ferret#private#lackcomplete Lack call ferret#private#lack(<f-args>)
+"
+" @command :Lack! {pattern} {options}
+"
+" Like |:Lack|, but returns all results irrespective of the value of
+" |g:FerretMaxResults|.
+"
+command! -bang -nargs=+ -complete=customlist,ferret#private#lackcomplete Lack call ferret#private#lack(<bang>0, <f-args>)
 
 ""
 " @command :Back {pattern} {options}
@@ -527,7 +546,13 @@ command! -nargs=+ -complete=customlist,ferret#private#lackcomplete Lack call fer
 " 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.
-command! -nargs=+ -complete=customlist,ferret#private#backcomplete Back call ferret#private#back(<f-args>)
+"
+" @command :Back! {pattern} {options}
+"
+" Like |:Back|, but returns all results irrespective of the value of
+" |g:FerretMaxResults|.
+"
+command! -bang -nargs=+ -complete=customlist,ferret#private#backcomplete Back call ferret#private#back(<bang>0, <f-args>)
 
 ""
 " @command :Black {pattern} {options}
@@ -537,7 +562,13 @@ command! -nargs=+ -complete=customlist,ferret#private#backcomplete Back call fer
 " `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.
-command! -nargs=+ -complete=customlist,ferret#private#blackcomplete Black call ferret#private#black(<f-args>)
+"
+" @command :Black! {pattern} {options}
+"
+" Like |:Black|, but returns all results irrespective of the value of
+" |g:FerretMaxResults|.
+"
+command! -bang -nargs=+ -complete=customlist,ferret#private#blackcomplete Black call ferret#private#black(<bang>0, <f-args>)
 
 ""
 " @command :Acks /{pattern}/{replacement}/