patch 8.2.0877: cannot get the search statistics

Problem:    Cannot get the search statistics.
Solution:   Add the searchcount() function. (Fujiwara Takuya, closes #4446)
diff --git a/src/testdir/test_search_stat.vim b/src/testdir/test_search_stat.vim
index 68d339f..7c2a195 100644
--- a/src/testdir/test_search_stat.vim
+++ b/src/testdir/test_search_stat.vim
@@ -9,14 +9,44 @@
   " Append 50 lines with text to search for, "foobar" appears 20 times
   call append(0, repeat(['foobar', 'foo', 'fooooobar', 'foba', 'foobar'], 10))
 
-  " match at second line
   call cursor(1, 1)
+
+  " searchcount() returns an empty dictionary when previous pattern was not set
+  call assert_equal({}, searchcount(#{pattern: ''}))
+  " but setting @/ should also work (even 'n' nor 'N' was executed)
+  " recompute the count when the last position is different.
+  call assert_equal(
+    \ #{current: 1, exact_match: 1, total: 40, incomplete: 0, maxcount: 99},
+    \ searchcount(#{pattern: 'foo'}))
+  call assert_equal(
+    \ #{current: 0, exact_match: 0, total: 10, incomplete: 0, maxcount: 99},
+    \ searchcount(#{pattern: 'fooooobar'}))
+  call assert_equal(
+    \ #{current: 0, exact_match: 0, total: 10, incomplete: 0, maxcount: 99},
+    \ searchcount(#{pattern: 'fooooobar', pos: [2, 1, 0]}))
+  call assert_equal(
+    \ #{current: 1, exact_match: 1, total: 10, incomplete: 0, maxcount: 99},
+    \ searchcount(#{pattern: 'fooooobar', pos: [3, 1, 0]}))
+  call assert_equal(
+    \ #{current: 1, exact_match: 0, total: 10, incomplete: 0, maxcount: 99},
+    \ searchcount(#{pattern: 'fooooobar', pos: [4, 1, 0]}))
+  call assert_equal(
+    \ #{current: 1, exact_match: 0, total: 2, incomplete: 2, maxcount: 1},
+    \ searchcount(#{pattern: 'fooooobar', pos: [4, 1, 0], maxcount: 1}))
+  call assert_equal(
+    \ #{current: 0, exact_match: 0, total: 2, incomplete: 2, maxcount: 1},
+    \ searchcount(#{pattern: 'fooooobar', maxcount: 1}))
+
+  " match at second line
   let messages_before = execute('messages')
   let @/ = 'fo*\(bar\?\)\?'
   let g:a = execute(':unsilent :norm! n')
   let stat = '\[2/50\]'
   let pat = escape(@/, '()*?'). '\s\+'
   call assert_match(pat .. stat, g:a)
+  call assert_equal(
+    \ #{current: 2, exact_match: 1, total: 50, incomplete: 0, maxcount: 99},
+    \ searchcount(#{recompute: 0}))
   " didn't get added to message history
   call assert_equal(messages_before, execute('messages'))
 
@@ -25,6 +55,9 @@
   let g:a = execute(':unsilent :norm! n')
   let stat = '\[50/50\]'
   call assert_match(pat .. stat, g:a)
+  call assert_equal(
+    \ #{current: 50, exact_match: 1, total: 50, incomplete: 0, maxcount: 99},
+    \ searchcount(#{recompute: 0}))
 
   " No search stat
   set shortmess+=S
@@ -32,6 +65,14 @@
   let stat = '\[2/50\]'
   let g:a = execute(':unsilent :norm! n')
   call assert_notmatch(pat .. stat, g:a)
+  call writefile(getline(1, '$'), 'sample.txt')
+  " n does not update search stat
+  call assert_equal(
+    \ #{current: 50, exact_match: 1, total: 50, incomplete: 0, maxcount: 99},
+    \ searchcount(#{recompute: 0}))
+  call assert_equal(
+    \ #{current: 2, exact_match: 1, total: 50, incomplete: 0, maxcount: 99},
+    \ searchcount(#{recompute: v:true}))
   set shortmess-=S
 
   " Many matches
@@ -41,10 +82,28 @@
   let g:a = execute(':unsilent :norm! n')
   let stat = '\[>99/>99\]'
   call assert_match(pat .. stat, g:a)
+  call assert_equal(
+    \ #{current: 100, exact_match: 0, total: 100, incomplete: 2, maxcount: 99},
+    \ searchcount(#{recompute: 0}))
+  call assert_equal(
+    \ #{current: 272, exact_match: 1, total: 280, incomplete: 0, maxcount: 0},
+    \ searchcount(#{recompute: v:true, maxcount: 0}))
+  call assert_equal(
+    \ #{current: 1, exact_match: 1, total: 280, incomplete: 0, maxcount: 0},
+    \ searchcount(#{recompute: 1, maxcount: 0, pos: [1, 1, 0]}))
   call cursor(line('$'), 1)
   let g:a = execute(':unsilent :norm! n')
   let stat = 'W \[1/>99\]'
   call assert_match(pat .. stat, g:a)
+  call assert_equal(
+    \ #{current: 1, exact_match: 1, total: 100, incomplete: 2, maxcount: 99},
+    \ searchcount(#{recompute: 0}))
+  call assert_equal(
+    \ #{current: 1, exact_match: 1, total: 280, incomplete: 0, maxcount: 0},
+    \ searchcount(#{recompute: 1, maxcount: 0}))
+  call assert_equal(
+    \ #{current: 271, exact_match: 1, total: 280, incomplete: 0, maxcount: 0},
+    \ searchcount(#{recompute: 1, maxcount: 0, pos: [line('$')-2, 1, 0]}))
 
   " Many matches
   call cursor(1, 1)
@@ -180,6 +239,12 @@
   call assert_match('^\s\+' .. stat, g:b)
   unmap n
 
+  " Time out
+  %delete _
+  call append(0, repeat(['foobar', 'foo', 'fooooobar', 'foba', 'foobar'], 100000))
+  call cursor(1, 1)
+  call assert_equal(1, searchcount(#{pattern: 'foo', maxcount: 0, timeout: 1}).incomplete)
+
   " Clean up
   set shortmess+=S
   " close the window