patch 8.0.0918: cannot get terminal window cursor shape or attributes

Problem:    Cannot get terminal window cursor shape or attributes.
Solution:   Support cursor shape, attributes and color.
diff --git a/src/terminal.c b/src/terminal.c
index e8727ee..fe1d5da 100644
--- a/src/terminal.c
+++ b/src/terminal.c
@@ -36,9 +36,7 @@
  * that buffer, attributes come from the scrollback buffer tl_scrollback.
  *
  * TODO:
- * - support different cursor shapes, colors and attributes
- * - make term_getcursor() return type (none/block/bar/underline) and
- *   attributes (color, blink, etc.)
+ * - cursor shape/color/blink in the GUI
  * - Make argument list work on MS-Windows. #1954
  * - MS-Windows: no redraw for 'updatetime'  #1915
  * - To set BS correctly, check get_stty(); Pass the fd of the pty.
@@ -143,6 +141,9 @@
 
     VTermPos	tl_cursor_pos;
     int		tl_cursor_visible;
+    int		tl_cursor_blink;
+    int		tl_cursor_shape;  /* 1: block, 2: underline, 3: bar */
+    char_u	*tl_cursor_color; /* NULL or allocated */
 
     int		tl_using_altscreen;
 };
@@ -155,6 +156,8 @@
  */
 static term_T *first_term = NULL;
 
+/* Terminal active in terminal_loop(). */
+static term_T *in_terminal_loop = NULL;
 
 #define MAX_ROW 999999	    /* used for tl_dirty_row_end to update all rows */
 #define KEY_BUF_LEN 200
@@ -256,6 +259,7 @@
 	return;
     term->tl_dirty_row_end = MAX_ROW;
     term->tl_cursor_visible = TRUE;
+    term->tl_cursor_shape = VTERM_PROP_CURSORSHAPE_BLOCK;
     term->tl_finish = opt->jo_term_finish;
     ga_init2(&term->tl_scrollback, sizeof(sb_line_T), 300);
 
@@ -517,6 +521,7 @@
     vim_free(term->tl_title);
     vim_free(term->tl_status_text);
     vim_free(term->tl_opencmd);
+    vim_free(term->tl_cursor_color);
     vim_free(term);
     buf->b_term = NULL;
 }
@@ -1158,6 +1163,35 @@
     }
 }
 
+static int did_change_cursor = FALSE;
+
+    static void
+may_set_cursor_props(term_T *term)
+{
+    if (in_terminal_loop == term)
+    {
+	if (term->tl_cursor_color != NULL)
+	    term_cursor_color(term->tl_cursor_color);
+	else
+	    term_cursor_color((char_u *)"");
+	/* do both blink and shape+blink, in case setting shape does not work */
+	term_cursor_blink(term->tl_cursor_blink);
+	term_cursor_shape(term->tl_cursor_shape, term->tl_cursor_blink);
+    }
+}
+
+    static void
+may_restore_cursor_props(void)
+{
+    if (did_change_cursor)
+    {
+	did_change_cursor = FALSE;
+	ui_cursor_shape_forced(TRUE);
+	term_cursor_color((char_u *)"");
+	term_cursor_blink(FALSE);
+    }
+}
+
 /*
  * Returns TRUE if the current window contains a terminal and we are sending
  * keys to the job.
@@ -1185,10 +1219,14 @@
 {
     int		c;
     int		termkey = 0;
+    int		ret;
+
+    in_terminal_loop = curbuf->b_term;
 
     if (*curwin->w_p_tk != NUL)
 	termkey = string_to_key(curwin->w_p_tk, TRUE);
     position_cursor(curwin, &curbuf->b_term->tl_cursor_pos);
+    may_set_cursor_props(curbuf->b_term);
 
     for (;;)
     {
@@ -1235,7 +1273,8 @@
 		{
 		    /* CTRL-\ CTRL-N : go to Terminal-Normal mode. */
 		    term_enter_normal_mode();
-		    return FAIL;
+		    ret = FAIL;
+		    goto theend;
 		}
 		/* Send both keys to the terminal. */
 		send_keys_to_term(curbuf->b_term, prev_c, TRUE);
@@ -1249,7 +1288,8 @@
 	    {
 		/* CTRL-W N : go to Terminal-Normal mode. */
 		term_enter_normal_mode();
-		return FAIL;
+		ret = FAIL;
+		goto theend;
 	    }
 	    else if (c == '"')
 	    {
@@ -1260,13 +1300,22 @@
 	    {
 		stuffcharReadbuff(Ctrl_W);
 		stuffcharReadbuff(c);
-		return OK;
+		ret = OK;
+		goto theend;
 	    }
 	}
 	if (send_keys_to_term(curbuf->b_term, c, TRUE) != OK)
-	    return OK;
+	{
+	    ret = OK;
+	    goto theend;
+	}
     }
-    return FAIL;
+    ret = FAIL;
+
+theend:
+    in_terminal_loop = NULL;
+    may_restore_cursor_props();
+    return ret;
 }
 
 /*
@@ -1303,7 +1352,7 @@
     static void
 may_toggle_cursor(term_T *term)
 {
-    if (curbuf == term->tl_buffer)
+    if (in_terminal_loop == term)
     {
 	if (term->tl_cursor_visible)
 	    cursor_on();
@@ -1385,6 +1434,22 @@
 	    out_flush();
 	    break;
 
+	case VTERM_PROP_CURSORBLINK:
+	    term->tl_cursor_blink = value->boolean;
+	    may_set_cursor_props(term);
+	    break;
+
+	case VTERM_PROP_CURSORSHAPE:
+	    term->tl_cursor_shape = value->number;
+	    may_set_cursor_props(term);
+	    break;
+
+	case VTERM_PROP_CURSORCOLOR:
+	    vim_free(term->tl_cursor_color);
+	    term->tl_cursor_color = vim_strsave((char_u *)value->string);
+	    may_set_cursor_props(term);
+	    break;
+
 	case VTERM_PROP_ALTSCREEN:
 	    /* TODO: do anything else? */
 	    term->tl_using_altscreen = value->boolean;
@@ -2076,17 +2141,30 @@
 f_term_getcursor(typval_T *argvars, typval_T *rettv)
 {
     buf_T	*buf = term_get_buf(argvars);
+    term_T	*term;
     list_T	*l;
+    dict_T	*d;
 
     if (rettv_list_alloc(rettv) == FAIL)
 	return;
     if (buf == NULL)
 	return;
+    term = buf->b_term;
 
     l = rettv->vval.v_list;
-    list_append_number(l, buf->b_term->tl_cursor_pos.row + 1);
-    list_append_number(l, buf->b_term->tl_cursor_pos.col + 1);
-    list_append_number(l, buf->b_term->tl_cursor_visible);
+    list_append_number(l, term->tl_cursor_pos.row + 1);
+    list_append_number(l, term->tl_cursor_pos.col + 1);
+
+    d = dict_alloc();
+    if (d != NULL)
+    {
+	dict_add_nr_str(d, "visible", term->tl_cursor_visible, NULL);
+	dict_add_nr_str(d, "blink", term->tl_cursor_blink, NULL);
+	dict_add_nr_str(d, "shape", term->tl_cursor_shape, NULL);
+	dict_add_nr_str(d, "color", 0L, term->tl_cursor_color == NULL
+				       ? (char_u *)"" : term->tl_cursor_color);
+	list_append_dict(l, d);
+    }
 }
 
 /*