patch 8.2.4591: cursor line not updated when a callback moves the cursor

Problem:    Cursor line not updated when a callback moves the cursor.
Solution:   Check if the cursor moved. (closes #9970)
diff --git a/src/drawscreen.c b/src/drawscreen.c
index 3a157e9..cdfcac0 100644
--- a/src/drawscreen.c
+++ b/src/drawscreen.c
@@ -1463,11 +1463,14 @@
 #ifdef FEAT_SYN_HL
     // remember what happened to the previous line, to know if
     // check_visual_highlight() can be used
-#define DID_NONE 1	// didn't update a line
-#define DID_LINE 2	// updated a normal line
-#define DID_FOLD 3	// updated a folded line
+# define DID_NONE 1	// didn't update a line
+# define DID_LINE 2	// updated a normal line
+# define DID_FOLD 3	// updated a folded line
     int		did_update = DID_NONE;
     linenr_T	syntax_last_parsed = 0;		// last parsed text line
+    // remember the current w_last_cursorline, it changes when drawing the new
+    // cursor line
+    linenr_T	last_cursorline = wp->w_last_cursorline;
 #endif
     linenr_T	mod_top = 0;
     linenr_T	mod_bot = 0;
@@ -2244,7 +2247,7 @@
 				))))
 #ifdef FEAT_SYN_HL
 		|| (wp->w_p_cul && (lnum == wp->w_cursor.lnum
-					     || lnum == wp->w_last_cursorline))
+						   || lnum == last_cursorline))
 #endif
 				)
 	{
@@ -3027,6 +3030,23 @@
 }
 #endif
 
+#if defined(FEAT_SYN_HL) || defined(PROTO)
+/*
+ * Check if the cursor moved and 'cursorline' is set.  Mark for a VALID redraw
+ * if needed.
+ */
+    void
+check_redraw_cursorline(void)
+{
+    // When 'cursorlineopt' is "screenline" need to redraw always.
+    if (curwin->w_p_cul
+	    && (curwin->w_last_cursorline != curwin->w_cursor.lnum
+		|| (curwin->w_p_culopt_flags & CULOPT_SCRLINE))
+	    && !char_avail())
+	redraw_later(VALID);
+}
+#endif
+
 /*
  * Invoked after an asynchronous callback is called.
  * If an echo command was used the cursor needs to be put back where
@@ -3071,6 +3091,10 @@
     }
     else if (State & (NORMAL | INSERT | TERMINAL))
     {
+#ifdef FEAT_SYN_HL
+	// might need to update for 'cursorline'
+	check_redraw_cursorline();
+#endif
 	// keep the command line if possible
 	update_screen(VALID_NO_UPDATE);
 	setcursor();
diff --git a/src/main.c b/src/main.c
index 80cff7c..7e8cbf0 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1386,12 +1386,7 @@
 
 #ifdef FEAT_SYN_HL
 	    // Might need to update for 'cursorline'.
-	    // When 'cursorlineopt' is "screenline" need to redraw always.
-	    if (curwin->w_p_cul
-		    && (curwin->w_last_cursorline != curwin->w_cursor.lnum
-			|| (curwin->w_p_culopt_flags & CULOPT_SCRLINE))
-		    && !char_avail())
-		redraw_later(VALID);
+	    check_redraw_cursorline();
 #endif
 	    if (VIsual_active)
 		update_curbuf(INVERTED); // update inverted part
diff --git a/src/proto/drawscreen.pro b/src/proto/drawscreen.pro
index c835019..573a2a4 100644
--- a/src/proto/drawscreen.pro
+++ b/src/proto/drawscreen.pro
@@ -8,6 +8,7 @@
 void update_debug_sign(buf_T *buf, linenr_T lnum);
 void updateWindow(win_T *wp);
 int redraw_asap(int type);
+void check_redraw_cursorline(void);
 void redraw_after_callback(int call_update_screen, int do_message);
 void redraw_later(int type);
 void redraw_win_later(win_T *wp, int type);
diff --git a/src/testdir/dumps/Test_cursorline_callback_1.dump b/src/testdir/dumps/Test_cursorline_callback_1.dump
new file mode 100644
index 0000000..c4f32ea
--- /dev/null
+++ b/src/testdir/dumps/Test_cursorline_callback_1.dump
@@ -0,0 +1,8 @@
+|a+0&#ffffff0@4| @69
+>b+8&&@4| @69
+|c+0&&@4| @69
+|d@4| @69
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+| +0#0000000&@56|4|,|1| @10|A|l@1| 
diff --git a/src/testdir/test_cursorline.vim b/src/testdir/test_cursorline.vim
index 245048b..2b29007 100644
--- a/src/testdir/test_cursorline.vim
+++ b/src/testdir/test_cursorline.vim
@@ -247,4 +247,30 @@
   call delete('Xtextfile')
 endfunc
 
+func Test_cursorline_callback()
+  CheckScreendump
+  CheckFeature timers
+
+  let lines =<< trim END
+      call setline(1, ['aaaaa', 'bbbbb', 'ccccc', 'ddddd'])
+      set cursorline
+      call cursor(4, 1)
+
+      func Func(timer)
+        call cursor(2, 1)
+      endfunc
+
+      call timer_start(300, 'Func')
+  END
+  call writefile(lines, 'Xcul_timer')
+
+  let buf = RunVimInTerminal('-S Xcul_timer', #{rows: 8})
+  call TermWait(buf, 310)
+  call VerifyScreenDump(buf, 'Test_cursorline_callback_1', {})
+
+  call StopVimInTerminal(buf)
+  call delete('Xcul_timer')
+endfunc
+
+
 " vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/version.c b/src/version.c
index 682fdc6..25b19f1 100644
--- a/src/version.c
+++ b/src/version.c
@@ -751,6 +751,8 @@
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    4591,
+/**/
     4590,
 /**/
     4589,