patch 8.2.0970: terminal properties are not available in Vim script

Problem:    Terminal properties are not available in Vim script.
Solution:   Add the terminalprops() function.
diff --git a/src/evalfunc.c b/src/evalfunc.c
index 1f53095..fe98636 100644
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -944,6 +944,7 @@
     {"term_setsize",	3, 3, FEARG_1,	  ret_void,	TERM_FUNC(f_term_setsize)},
     {"term_start",	1, 2, FEARG_1,	  ret_number,	TERM_FUNC(f_term_start)},
     {"term_wait",	1, 2, FEARG_1,	  ret_void,	TERM_FUNC(f_term_wait)},
+    {"terminalprops",	0, 0, 0,	  ret_dict_string, f_terminalprops},
     {"test_alloc_fail",	3, 3, FEARG_1,	  ret_void,	f_test_alloc_fail},
     {"test_autochdir",	0, 0, 0,	  ret_void,	f_test_autochdir},
     {"test_feedinput",	1, 1, FEARG_1,	  ret_void,	f_test_feedinput},
diff --git a/src/globals.h b/src/globals.h
index b8fd231..e5dcb7b 100644
--- a/src/globals.h
+++ b/src/globals.h
@@ -1839,6 +1839,7 @@
 EXTERN int  ignore_redraw_flag_for_testing INIT(= FALSE);
 EXTERN int  nfa_fail_for_testing INIT(= FALSE);
 EXTERN int  no_query_mouse_for_testing INIT(= FALSE);
+EXTERN int  reset_term_props_on_termresponse INIT(= FALSE);
 
 EXTERN int  in_free_unref_items INIT(= FALSE);
 #endif
diff --git a/src/main.c b/src/main.c
index f686a5f..39e67e9 100644
--- a/src/main.c
+++ b/src/main.c
@@ -407,6 +407,10 @@
     init_highlight(TRUE, FALSE); // set the default highlight groups
     TIME_MSG("init highlight");
 
+#if defined(FEAT_TERMRESPONSE)
+    init_term_props(TRUE);
+#endif
+
 #ifdef FEAT_EVAL
     // Set the break level after the terminal is initialized.
     debug_break_level = params.use_debug_break_level;
diff --git a/src/proto/term.pro b/src/proto/term.pro
index 40934ea..1b37802 100644
--- a/src/proto/term.pro
+++ b/src/proto/term.pro
@@ -1,6 +1,8 @@
 /* term.c */
 guicolor_T termgui_get_color(char_u *name);
 guicolor_T termgui_mch_get_rgb(guicolor_T color);
+void init_term_props(int all);
+void f_terminalprops(typval_T *argvars, typval_T *rettv);
 void set_color_count(int nr);
 int set_termname(char_u *term);
 void getlinecol(long *cp, long *rp);
diff --git a/src/term.c b/src/term.c
index 82b1126..e75fddb 100644
--- a/src/term.c
+++ b/src/term.c
@@ -1470,7 +1470,7 @@
  * When "all" is FALSE only set those that are detected from the version
  * response.
  */
-    static void
+    void
 init_term_props(int all)
 {
     int i;
@@ -1490,6 +1490,29 @@
 }
 #endif
 
+#if defined(FEAT_EVAL) || defined(PROTO)
+    void
+f_terminalprops(typval_T *argvars UNUSED, typval_T *rettv)
+{
+# ifdef FEAT_TERMRESPONSE
+    int i;
+# endif
+
+    if (rettv_dict_alloc(rettv) != OK)
+	return;
+# ifdef FEAT_TERMRESPONSE
+    for (i = 0; i < TPR_COUNT; ++i)
+    {
+	char_u	value[2];
+
+	value[0] = term_props[i].tpr_status;
+	value[1] = NUL;
+	dict_add_string(rettv->vval.v_dict, term_props[i].tpr_name, value);
+    }
+# endif
+}
+#endif
+
     static struct builtin_term *
 find_builtin_term(char_u *term)
 {
@@ -3676,8 +3699,6 @@
 {
     int	    did_send = FALSE;
 
-    init_term_props(TRUE);
-
     if (!can_get_termresponse() || starting != 0 || *T_U7 == NUL)
 	return;
 
@@ -4516,7 +4537,8 @@
 
     // Reset terminal properties that are set based on the termresponse.
     // Mainly useful for tests that send the termresponse multiple times.
-    init_term_props(FALSE);
+    // For testing all props can be reset.
+    init_term_props(reset_term_props_on_termresponse);
 
     // If this code starts with CSI, you can bet that the
     // terminal uses 8-bit codes.
diff --git a/src/testdir/test_termcodes.vim b/src/testdir/test_termcodes.vim
index 86589b2..82f5f41 100644
--- a/src/testdir/test_termcodes.vim
+++ b/src/testdir/test_termcodes.vim
@@ -922,6 +922,7 @@
 func Test_xx01_term_style_response()
   " Termresponse is only parsed when t_RV is not empty.
   set t_RV=x
+  call test_override('term_props', 1)
 
   " send the termresponse to trigger requesting the XT codes
   let seq = "\<Esc>[>41;337;0c"
@@ -932,7 +933,15 @@
   call feedkeys(seq, 'Lx!')
   call assert_equal(seq, v:termstyleresp)
 
+  call assert_equal(#{
+        \ cursor_style: 'u',
+        \ cursor_blink_mode: 'u',
+        \ underline_rgb: 'u',
+        \ mouse: 's'
+        \ }, terminalprops())
+
   set t_RV=
+  call test_override('term_props', 0)
 endfunc
 
 " This checks the iTerm2 version response.
@@ -941,6 +950,7 @@
 func Test_xx02_iTerm2_response()
   " Termresponse is only parsed when t_RV is not empty.
   set t_RV=x
+  call test_override('term_props', 1)
 
   " Old versions of iTerm2 used a different style term response.
   set ttymouse=xterm
@@ -957,7 +967,15 @@
   call assert_equal(seq, v:termresponse)
   call assert_equal('sgr', &ttymouse)
 
+  call assert_equal(#{
+        \ cursor_style: 'n',
+        \ cursor_blink_mode: 'u',
+        \ underline_rgb: 'u',
+        \ mouse: 's'
+        \ }, terminalprops())
+
   set t_RV=
+  call test_override('term_props', 0)
 endfunc
 
 " This checks the libvterm version response.
@@ -966,6 +984,7 @@
 func Test_xx03_libvterm_response()
   " Termresponse is only parsed when t_RV is not empty.
   set t_RV=x
+  call test_override('term_props', 1)
 
   set ttymouse=xterm
   call test_option_not_set('ttymouse')
@@ -974,7 +993,15 @@
   call assert_equal(seq, v:termresponse)
   call assert_equal('sgr', &ttymouse)
 
+  call assert_equal(#{
+        \ cursor_style: 'n',
+        \ cursor_blink_mode: 'u',
+        \ underline_rgb: 'u',
+        \ mouse: 's'
+        \ }, terminalprops())
+
   set t_RV=
+  call test_override('term_props', 0)
 endfunc
 
 " This checks the Mac Terminal.app version response.
@@ -983,6 +1010,7 @@
 func Test_xx04_Mac_Terminal_response()
   " Termresponse is only parsed when t_RV is not empty.
   set t_RV=x
+  call test_override('term_props', 1)
 
   set ttymouse=xterm
   call test_option_not_set('ttymouse')
@@ -991,10 +1019,18 @@
   call assert_equal(seq, v:termresponse)
   call assert_equal('sgr', &ttymouse)
 
+  call assert_equal(#{
+        \ cursor_style: 'n',
+        \ cursor_blink_mode: 'u',
+        \ underline_rgb: 'y',
+        \ mouse: 's'
+        \ }, terminalprops())
+
   " Reset is_not_xterm and is_mac_terminal.
   set t_RV=
   set term=xterm
   set t_RV=x
+  call test_override('term_props', 0)
 endfunc
 
 " This checks the mintty version response.
@@ -1003,6 +1039,7 @@
 func Test_xx05_mintty_response()
   " Termresponse is only parsed when t_RV is not empty.
   set t_RV=x
+  call test_override('term_props', 1)
 
   set ttymouse=xterm
   call test_option_not_set('ttymouse')
@@ -1011,7 +1048,15 @@
   call assert_equal(seq, v:termresponse)
   call assert_equal('sgr', &ttymouse)
 
+  call assert_equal(#{
+        \ cursor_style: 'n',
+        \ cursor_blink_mode: 'u',
+        \ underline_rgb: 'y',
+        \ mouse: 's'
+        \ }, terminalprops())
+
   set t_RV=
+  call test_override('term_props', 0)
 endfunc
 
 " This checks the screen version response.
@@ -1020,6 +1065,7 @@
 func Test_xx06_screen_response()
   " Termresponse is only parsed when t_RV is not empty.
   set t_RV=x
+  call test_override('term_props', 1)
 
   " Old versions of screen don't support SGR mouse mode.
   set ttymouse=xterm
@@ -1037,7 +1083,15 @@
   call assert_equal(seq, v:termresponse)
   call assert_equal('sgr', &ttymouse)
 
+  call assert_equal(#{
+        \ cursor_style: 'n',
+        \ cursor_blink_mode: 'n',
+        \ underline_rgb: 'y',
+        \ mouse: 's'
+        \ }, terminalprops())
+
   set t_RV=
+  call test_override('term_props', 0)
 endfunc
 
 " This checks the xterm version response.
@@ -1046,6 +1100,7 @@
 func Test_xx07_xterm_response()
   " Termresponse is only parsed when t_RV is not empty.
   set t_RV=x
+  call test_override('term_props', 1)
 
   " Do Terminal.app first to check that is_mac_terminal is reset.
   set ttymouse=xterm
@@ -1066,6 +1121,13 @@
   call assert_equal(seq, v:termresponse)
   call assert_equal('xterm', &ttymouse)
 
+  call assert_equal(#{
+        \ cursor_style: 'n',
+        \ cursor_blink_mode: 'u',
+        \ underline_rgb: 'y',
+        \ mouse: 'u'
+        \ }, terminalprops())
+
   " xterm >= 95 < 277 "xterm2"
   set ttymouse=xterm
   call test_option_not_set('ttymouse')
@@ -1074,6 +1136,13 @@
   call assert_equal(seq, v:termresponse)
   call assert_equal('xterm2', &ttymouse)
 
+  call assert_equal(#{
+        \ cursor_style: 'n',
+        \ cursor_blink_mode: 'u',
+        \ underline_rgb: 'u',
+        \ mouse: '2'
+        \ }, terminalprops())
+
   " xterm >= 277: "sgr"
   set ttymouse=xterm
   call test_option_not_set('ttymouse')
@@ -1082,7 +1151,30 @@
   call assert_equal(seq, v:termresponse)
   call assert_equal('sgr', &ttymouse)
 
+  call assert_equal(#{
+        \ cursor_style: 'n',
+        \ cursor_blink_mode: 'u',
+        \ underline_rgb: 'u',
+        \ mouse: 's'
+        \ }, terminalprops())
+
+  " xterm >= 279: "sgr" and cursor_style not reset
+  set ttymouse=xterm
+  call test_option_not_set('ttymouse')
+  let seq = "\<Esc>[>0;279;0c"
+  call feedkeys(seq, 'Lx!')
+  call assert_equal(seq, v:termresponse)
+  call assert_equal('sgr', &ttymouse)
+
+  call assert_equal(#{
+        \ cursor_style: 'u',
+        \ cursor_blink_mode: 'u',
+        \ underline_rgb: 'u',
+        \ mouse: 's'
+        \ }, terminalprops())
+
   set t_RV=
+  call test_override('term_props', 0)
 endfunc
 
 func Test_get_termcode()
diff --git a/src/testing.c b/src/testing.c
index c01ae3d..83e3fe4 100644
--- a/src/testing.c
+++ b/src/testing.c
@@ -854,6 +854,8 @@
 	    no_query_mouse_for_testing = val;
 	else if (STRCMP(name, (char_u *)"no_wait_return") == 0)
 	    no_wait_return = val;
+	else if (STRCMP(name, (char_u *)"term_props") == 0)
+	    reset_term_props_on_termresponse = val;
 	else if (STRCMP(name, (char_u *)"ALL") == 0)
 	{
 	    disable_char_avail_for_testing = FALSE;
@@ -861,6 +863,7 @@
 	    ignore_redraw_flag_for_testing = FALSE;
 	    nfa_fail_for_testing = FALSE;
 	    no_query_mouse_for_testing = FALSE;
+	    reset_term_props_on_termresponse = FALSE;
 	    if (save_starting >= 0)
 	    {
 		starting = save_starting;
diff --git a/src/version.c b/src/version.c
index 1c660ed..052f030 100644
--- a/src/version.c
+++ b/src/version.c
@@ -755,6 +755,8 @@
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    970,
+/**/
     969,
 /**/
     968,