patch 8.2.3110: a pattern that matches the cursor position is complicated

Problem:    A pattern that matches the cursor position is bit complicated.
Solution:   Use a dot to indicate the cursor line and column. (Christian
            Brabandt, closes #8497, closes #8179)
diff --git a/src/errors.h b/src/errors.h
index f2624df..7524b80 100644
--- a/src/errors.h
+++ b/src/errors.h
@@ -488,3 +488,5 @@
 	INIT(= N_("E1202: No white space allowed after '%s': %s"));
 EXTERN char e_dot_can_only_be_used_on_dictionary_str[]
 	INIT(= N_("E1203: Dot can only be used on a dictionary: %s"));
+EXTERN char e_regexp_number_after_dot_pos_search[]
+	INIT(= N_("E1204: No Number allowed after .: '\\%%%c'"));
diff --git a/src/regexp_bt.c b/src/regexp_bt.c
index 70ddfe9..dae6d51 100644
--- a/src/regexp_bt.c
+++ b/src/regexp_bt.c
@@ -1628,14 +1628,20 @@
 
 		default:
 			  if (VIM_ISDIGIT(c) || c == '<' || c == '>'
-								 || c == '\'')
+						|| c == '\'' || c == '.')
 			  {
 			      long_u	n = 0;
 			      int	cmp;
+			      int	cur = FALSE;
 
 			      cmp = c;
 			      if (cmp == '<' || cmp == '>')
 				  c = getchr();
+			      if (no_Magic(c) == '.')
+			      {
+				  cur = TRUE;
+				  c = getchr();
+			      }
 			      while (VIM_ISDIGIT(c))
 			      {
 				  n = n * 10 + (c - '0');
@@ -1657,16 +1663,42 @@
 			      }
 			      else if (c == 'l' || c == 'c' || c == 'v')
 			      {
+				  if (cur && n)
+				  {
+				    semsg(_(e_regexp_number_after_dot_pos_search), no_Magic(c));
+				    rc_did_emsg = TRUE;
+				    return NULL;
+				  }
 				  if (c == 'l')
 				  {
+				      if (cur)
+					  n = curwin->w_cursor.lnum;
 				      ret = regnode(RE_LNUM);
 				      if (save_prev_at_start)
 					  at_start = TRUE;
 				  }
 				  else if (c == 'c')
+				  {
+				      if (cur)
+				      {
+					  n = curwin->w_cursor.col;
+					  n++;
+				      }
 				      ret = regnode(RE_COL);
+				  }
 				  else
+				  {
+				      if (cur)
+				      {
+					  colnr_T vcol = 0;
+
+					  getvvcol(curwin, &curwin->w_cursor,
+							    NULL, NULL, &vcol);
+					  ++vcol;
+					  n = vcol;
+				      }
 				      ret = regnode(RE_VCOL);
+				  }
 				  if (ret == JUST_CALC_SIZE)
 				      regsize += 5;
 				  else
diff --git a/src/regexp_nfa.c b/src/regexp_nfa.c
index 2ed1868..7dff195 100644
--- a/src/regexp_nfa.c
+++ b/src/regexp_nfa.c
@@ -1707,12 +1707,23 @@
 		    {
 			long_u	n = 0;
 			int	cmp = c;
+			int	cur = FALSE;
 
 			if (c == '<' || c == '>')
 			    c = getchr();
+			if (no_Magic(c) == '.')
+			{
+			    cur = TRUE;
+			    c = getchr();
+			}
 			while (VIM_ISDIGIT(c))
 			{
-			    long_u tmp = n * 10 + (c - '0');
+			    long_u tmp;
+
+			    if (cur)
+				semsg(_(e_regexp_number_after_dot_pos_search),
+								 no_Magic(c));
+			    tmp = n * 10 + (c - '0');
 
 			    if (tmp < n)
 			    {
@@ -1729,6 +1740,8 @@
 
 			    if (c == 'l')
 			    {
+				if (cur)
+				    n = curwin->w_cursor.lnum;
 				// \%{n}l  \%{n}<l  \%{n}>l
 				EMIT(cmp == '<' ? NFA_LNUM_LT :
 				     cmp == '>' ? NFA_LNUM_GT : NFA_LNUM);
@@ -1736,11 +1749,26 @@
 				    at_start = TRUE;
 			    }
 			    else if (c == 'c')
+			    {
+				if (cur)
+				{
+				    n = curwin->w_cursor.col;
+				    n++;
+				}
 				// \%{n}c  \%{n}<c  \%{n}>c
 				EMIT(cmp == '<' ? NFA_COL_LT :
 				     cmp == '>' ? NFA_COL_GT : NFA_COL);
+			    }
 			    else
 			    {
+				if (cur)
+				{
+				    colnr_T vcol = 0;
+
+				    getvvcol(curwin, &curwin->w_cursor,
+							    NULL, NULL, &vcol);
+				    n = ++vcol;
+				}
 				// \%{n}v  \%{n}<v  \%{n}>v
 				EMIT(cmp == '<' ? NFA_VCOL_LT :
 				     cmp == '>' ? NFA_VCOL_GT : NFA_VCOL);
diff --git a/src/testdir/test_regexp_latin.vim b/src/testdir/test_regexp_latin.vim
index e53a8da..c487b27 100644
--- a/src/testdir/test_regexp_latin.vim
+++ b/src/testdir/test_regexp_latin.vim
@@ -947,4 +947,94 @@
   close!
 endfunc
 
+" Check patterns matching cursor position.
+func s:curpos_test2()
+  new
+  call setline(1, ['1', '2 foobar eins zwei drei vier fünf sechse',
+        \ '3 foobar eins zwei drei vier fünf sechse',
+        \ '4 foobar eins zwei drei vier fünf sechse',
+        \ '5	foobar eins zwei drei vier fünf sechse',
+        \ '6	foobar eins zwei drei vier fünf sechse',
+        \ '7	foobar eins zwei drei vier fünf sechse'])
+  call setpos('.', [0, 2, 10, 0])
+  s/\%.c.*//g
+  call setpos('.', [0, 3, 15, 0])
+  s/\%.l.*//g
+  call setpos('.', [0, 5, 3, 0])
+  s/\%.v.*/_/g
+  call assert_equal(['1',
+        \ '2 foobar ',
+        \ '',
+        \ '4 foobar eins zwei drei vier fünf sechse',
+        \ '5	_',
+        \ '6	foobar eins zwei drei vier fünf sechse',
+        \ '7	foobar eins zwei drei vier fünf sechse'],
+        \ getline(1, '$'))
+  call assert_fails('call search("\\%.1l")', 'E1204:')
+  call assert_fails('call search("\\%.1c")', 'E1204:')
+  call assert_fails('call search("\\%.1v")', 'E1204:')
+  bwipe!
+endfunc
+
+" Check patterns matching before or after cursor position.
+func s:curpos_test3()
+  new
+  call setline(1, ['1', '2 foobar eins zwei drei vier fünf sechse',
+        \ '3 foobar eins zwei drei vier fünf sechse',
+        \ '4 foobar eins zwei drei vier fünf sechse',
+        \ '5	foobar eins zwei drei vier fünf sechse',
+        \ '6	foobar eins zwei drei vier fünf sechse',
+        \ '7	foobar eins zwei drei vier fünf sechse'])
+  call setpos('.', [0, 2, 10, 0])
+  " Note: This removes all columns, except for the column directly in front of
+  " the cursor. Bug????
+  :s/^.*\%<.c//
+  call setpos('.', [0, 3, 10, 0])
+  :s/\%>.c.*$//
+  call setpos('.', [0, 5, 4, 0])
+  " Note: This removes all columns, except for the column directly in front of
+  " the cursor. Bug????
+  :s/^.*\%<.v/_/
+  call setpos('.', [0, 6, 4, 0])
+  :s/\%>.v.*$/_/
+  call assert_equal(['1',
+        \ ' eins zwei drei vier fünf sechse',
+        \ '3 foobar e',
+        \ '4 foobar eins zwei drei vier fünf sechse',
+        \ '_foobar eins zwei drei vier fünf sechse',
+        \ '6	fo_',
+        \ '7	foobar eins zwei drei vier fünf sechse'],
+        \ getline(1, '$'))
+  sil %d
+  call setline(1, ['1', '2 foobar eins zwei drei vier fünf sechse',
+        \ '3 foobar eins zwei drei vier fünf sechse',
+        \ '4 foobar eins zwei drei vier fünf sechse',
+        \ '5	foobar eins zwei drei vier fünf sechse',
+        \ '6	foobar eins zwei drei vier fünf sechse',
+        \ '7	foobar eins zwei drei vier fünf sechse'])
+  call setpos('.', [0, 4, 4, 0])
+  %s/\%<.l.*//
+  call setpos('.', [0, 5, 4, 0])
+  %s/\%>.l.*//
+  call assert_equal(['', '', '',
+        \ '4 foobar eins zwei drei vier fünf sechse',
+        \ '5	foobar eins zwei drei vier fünf sechse',
+        \ '', ''],
+        \ getline(1, '$'))
+  bwipe!
+endfunc
+
+" Test that matching below, at or after the
+" cursor position work
+func Test_matching_pos()
+  for val in range(3)
+    exe "set re=" .. val
+    " Match at cursor position
+    call s:curpos_test2()
+    " Match before or after cursor position
+    call s:curpos_test3()
+  endfor
+  set re&
+endfunc
+
 " vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/version.c b/src/version.c
index a36ec80..b448822 100644
--- a/src/version.c
+++ b/src/version.c
@@ -756,6 +756,8 @@
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    3110,
+/**/
     3109,
 /**/
     3108,