mirror of
				https://github.com/neovim/neovim.git
				synced 2025-10-26 12:27:24 +00:00 
			
		
		
		
	 Matthieu Coudron
					Matthieu Coudron
				
			
				
					committed by
					
						 Justin M. Keyes
						Justin M. Keyes
					
				
			
			
				
	
			
			
			 Justin M. Keyes
						Justin M. Keyes
					
				
			
						parent
						
							16babc6687
						
					
				
				
					commit
					dd4a5fcbb6
				
			| @@ -12,6 +12,7 @@ | |||||||
| #include "nvim/api/private/defs.h" | #include "nvim/api/private/defs.h" | ||||||
| #include "nvim/api/private/helpers.h" | #include "nvim/api/private/helpers.h" | ||||||
| #include "nvim/popupmnu.h" | #include "nvim/popupmnu.h" | ||||||
|  | #include "nvim/cursor_shape.h" | ||||||
|  |  | ||||||
| #ifdef INCLUDE_GENERATED_DECLARATIONS | #ifdef INCLUDE_GENERATED_DECLARATIONS | ||||||
| # include "api/ui.c.generated.h" | # include "api/ui.c.generated.h" | ||||||
| @@ -69,6 +70,7 @@ void nvim_ui_attach(uint64_t channel_id, Integer width, Integer height, | |||||||
|   ui->clear = remote_ui_clear; |   ui->clear = remote_ui_clear; | ||||||
|   ui->eol_clear = remote_ui_eol_clear; |   ui->eol_clear = remote_ui_eol_clear; | ||||||
|   ui->cursor_goto = remote_ui_cursor_goto; |   ui->cursor_goto = remote_ui_cursor_goto; | ||||||
|  |   ui->cursor_style_set = remote_ui_cursor_style_set; | ||||||
|   ui->update_menu = remote_ui_update_menu; |   ui->update_menu = remote_ui_update_menu; | ||||||
|   ui->busy_start = remote_ui_busy_start; |   ui->busy_start = remote_ui_busy_start; | ||||||
|   ui->busy_stop = remote_ui_busy_stop; |   ui->busy_stop = remote_ui_busy_stop; | ||||||
| @@ -298,6 +300,14 @@ static void remote_ui_scroll(UI *ui, int count) | |||||||
|   push_call(ui, "scroll", args); |   push_call(ui, "scroll", args); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | static void remote_ui_cursor_style_set(UI *ui, Dictionary styles) | ||||||
|  | { | ||||||
|  |   Array args = ARRAY_DICT_INIT; | ||||||
|  |   Object copy = copy_object(DICTIONARY_OBJ(styles)); | ||||||
|  |   ADD(args, copy); | ||||||
|  |   push_call(ui, "cursor_style_set", args); | ||||||
|  | } | ||||||
|  |  | ||||||
| static void remote_ui_highlight_set(UI *ui, HlAttrs attrs) | static void remote_ui_highlight_set(UI *ui, HlAttrs attrs) | ||||||
| { | { | ||||||
|   Array args = ARRAY_DICT_INIT; |   Array args = ARRAY_DICT_INIT; | ||||||
|   | |||||||
| @@ -7,40 +7,84 @@ | |||||||
| #include "nvim/charset.h" | #include "nvim/charset.h" | ||||||
| #include "nvim/strings.h" | #include "nvim/strings.h" | ||||||
| #include "nvim/syntax.h" | #include "nvim/syntax.h" | ||||||
|  | #include "nvim/api/private/helpers.h" | ||||||
|  | #include "nvim/ui.h" | ||||||
|  |  | ||||||
| /* | /// Handling of cursor and mouse pointer shapes in various modes. | ||||||
|  * Handling of cursor and mouse pointer shapes in various modes. |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| static cursorentry_T shape_table[SHAPE_IDX_COUNT] = | static cursorentry_T shape_table[SHAPE_IDX_COUNT] = | ||||||
| { | { | ||||||
|   /* The values will be filled in from the 'guicursor' and 'mouseshape' |   // The values will be filled in from the 'guicursor' and 'mouseshape' | ||||||
|    * defaults when Vim starts. |   // defaults when Vim starts. | ||||||
|    * Adjust the SHAPE_IDX_ defines when making changes! */ |   // Adjust the SHAPE_IDX_ defines when making changes! | ||||||
|   {0, 0, 0, 700L, 400L, 250L, 0, 0, "n", SHAPE_CURSOR+SHAPE_MOUSE}, |   { "normal", | ||||||
|   {0, 0, 0, 700L, 400L, 250L, 0, 0, "v", SHAPE_CURSOR+SHAPE_MOUSE}, |     0, 0, 0, 700L, 400L, 250L, 0, 0, "n", SHAPE_CURSOR+SHAPE_MOUSE }, | ||||||
|   {0, 0, 0, 700L, 400L, 250L, 0, 0, "i", SHAPE_CURSOR+SHAPE_MOUSE}, |   { "visual", | ||||||
|   {0, 0, 0, 700L, 400L, 250L, 0, 0, "r", SHAPE_CURSOR+SHAPE_MOUSE}, |     0, 0, 0, 700L, 400L, 250L, 0, 0, "v", SHAPE_CURSOR+SHAPE_MOUSE }, | ||||||
|   {0, 0, 0, 700L, 400L, 250L, 0, 0, "c", SHAPE_CURSOR+SHAPE_MOUSE}, |   { "insert", | ||||||
|   {0, 0, 0, 700L, 400L, 250L, 0, 0, "ci", SHAPE_CURSOR+SHAPE_MOUSE}, |     0, 0, 0, 700L, 400L, 250L, 0, 0, "i", SHAPE_CURSOR+SHAPE_MOUSE }, | ||||||
|   {0, 0, 0, 700L, 400L, 250L, 0, 0, "cr", SHAPE_CURSOR+SHAPE_MOUSE}, |   { "replace", | ||||||
|   {0, 0, 0, 700L, 400L, 250L, 0, 0, "o", SHAPE_CURSOR+SHAPE_MOUSE}, |     0, 0, 0, 700L, 400L, 250L, 0, 0, "r", SHAPE_CURSOR+SHAPE_MOUSE }, | ||||||
|   {0, 0, 0, 700L, 400L, 250L, 0, 0, "ve", SHAPE_CURSOR+SHAPE_MOUSE}, |   { "cmd_normal", | ||||||
|   {0, 0, 0,   0L,   0L,   0L, 0, 0, "e", SHAPE_MOUSE}, |     0, 0, 0, 700L, 400L, 250L, 0, 0, "c", SHAPE_CURSOR+SHAPE_MOUSE }, | ||||||
|   {0, 0, 0,   0L,   0L,   0L, 0, 0, "s", SHAPE_MOUSE}, |   { "cmd_insert", 0, | ||||||
|   {0, 0, 0,   0L,   0L,   0L, 0, 0, "sd", SHAPE_MOUSE}, |     0, 0, 700L, 400L, 250L, 0, 0, "ci", SHAPE_CURSOR+SHAPE_MOUSE }, | ||||||
|   {0, 0, 0,   0L,   0L,   0L, 0, 0, "vs", SHAPE_MOUSE}, |   { "cmd_replace", | ||||||
|   {0, 0, 0,   0L,   0L,   0L, 0, 0, "vd", SHAPE_MOUSE}, |     0, 0, 0, 700L, 400L, 250L, 0, 0, "cr", SHAPE_CURSOR+SHAPE_MOUSE }, | ||||||
|   {0, 0, 0,   0L,   0L,   0L, 0, 0, "m", SHAPE_MOUSE}, |   { "pending", | ||||||
|   {0, 0, 0,   0L,   0L,   0L, 0, 0, "ml", SHAPE_MOUSE}, |     0, 0, 0, 700L, 400L, 250L, 0, 0, "o", SHAPE_CURSOR+SHAPE_MOUSE }, | ||||||
|   {0, 0, 0, 100L, 100L, 100L, 0, 0, "sm", SHAPE_CURSOR}, |   { "visual_select", | ||||||
|  |     0, 0, 0, 700L, 400L, 250L, 0, 0, "ve", SHAPE_CURSOR+SHAPE_MOUSE }, | ||||||
|  |   { "cmd_line", 0, 0, 0,   0L,   0L,   0L, 0, 0, "e", SHAPE_MOUSE }, | ||||||
|  |   { "statusline", 0, 0, 0,   0L,   0L,   0L, 0, 0, "s", SHAPE_MOUSE }, | ||||||
|  |   { "drag_statusline", 0, 0, 0,   0L,   0L,   0L, 0, 0, "sd", SHAPE_MOUSE }, | ||||||
|  |   { "vsep", 0, 0, 0,   0L,   0L,   0L, 0, 0, "vs", SHAPE_MOUSE }, | ||||||
|  |   { "vdrag", 0, 0, 0,   0L,   0L,   0L, 0, 0, "vd", SHAPE_MOUSE }, | ||||||
|  |   { "more", 0, 0, 0,   0L,   0L,   0L, 0, 0, "m", SHAPE_MOUSE }, | ||||||
|  |   { "more_lastline", 0, 0, 0,   0L,   0L,   0L, 0, 0, "ml", SHAPE_MOUSE }, | ||||||
|  |   { "match_paren", 0, 0, 0, 100L, 100L, 100L, 0, 0, "sm", SHAPE_CURSOR }, | ||||||
| }; | }; | ||||||
|  |  | ||||||
| /* | /// Converts cursor_shapes into a Dictionary of dictionaries | ||||||
|  * Parse the 'guicursor' option ("what" is SHAPE_CURSOR) or 'mouseshape' | /// @return a dictionary of the form {"normal" : { "cursor_shape": ... }, ...} | ||||||
|  * ("what" is SHAPE_MOUSE). | Dictionary cursor_shape_dict(void) | ||||||
|  * Returns error message for an illegal option, NULL otherwise. | { | ||||||
|  */ |   Dictionary all = ARRAY_DICT_INIT; | ||||||
|  |  | ||||||
|  |   for (int i = 0; i < SHAPE_IDX_COUNT; i++) { | ||||||
|  |     Dictionary dic = ARRAY_DICT_INIT; | ||||||
|  |     cursorentry_T *cur = &shape_table[i]; | ||||||
|  |     if (cur->used_for & SHAPE_MOUSE) { | ||||||
|  |       PUT(dic, "mouse_shape", INTEGER_OBJ(cur->mshape)); | ||||||
|  |     } | ||||||
|  |     if (cur->used_for & SHAPE_CURSOR) { | ||||||
|  |       String shape_str; | ||||||
|  |       switch (cur->shape) { | ||||||
|  |         case SHAPE_BLOCK: shape_str = cstr_to_string("block"); break; | ||||||
|  |         case SHAPE_VER: shape_str = cstr_to_string("vertical"); break; | ||||||
|  |         case SHAPE_HOR: shape_str = cstr_to_string("horizontal"); break; | ||||||
|  |         default: shape_str = cstr_to_string("unknown"); | ||||||
|  |       } | ||||||
|  |       PUT(dic, "cursor_shape", STRING_OBJ(shape_str)); | ||||||
|  |       PUT(dic, "cell_percentage", INTEGER_OBJ(cur->percentage)); | ||||||
|  |       PUT(dic, "blinkwait", INTEGER_OBJ(cur->blinkwait)); | ||||||
|  |       PUT(dic, "blinkon", INTEGER_OBJ(cur->blinkon)); | ||||||
|  |       PUT(dic, "blinkoff", INTEGER_OBJ(cur->blinkoff)); | ||||||
|  |       PUT(dic, "hl_id", INTEGER_OBJ(cur->id)); | ||||||
|  |       PUT(dic, "id_lm", INTEGER_OBJ(cur->id_lm)); | ||||||
|  |     } | ||||||
|  |     PUT(dic, "short_name", STRING_OBJ(cstr_to_string(cur->name))); | ||||||
|  |  | ||||||
|  |     PUT(all, cur->full_name, DICTIONARY_OBJ(dic)); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   return all; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /// Parse the 'guicursor' option | ||||||
|  | /// | ||||||
|  | /// @param what either SHAPE_CURSOR or SHAPE_MOUSE ('mouseshape') | ||||||
|  | /// | ||||||
|  | /// @returns error message for an illegal option, NULL otherwise. | ||||||
| char_u *parse_shape_opt(int what) | char_u *parse_shape_opt(int what) | ||||||
| { | { | ||||||
|   char_u      *modep; |   char_u      *modep; | ||||||
| @@ -71,19 +115,18 @@ char_u *parse_shape_opt(int what) | |||||||
|         return (char_u *)N_("E546: Illegal mode"); |         return (char_u *)N_("E546: Illegal mode"); | ||||||
|       commap = vim_strchr(modep, ','); |       commap = vim_strchr(modep, ','); | ||||||
|  |  | ||||||
|       /* |       // Repeat for all mode's before the colon. | ||||||
|        * Repeat for all mode's before the colon. |       // For the 'a' mode, we loop to handle all the modes. | ||||||
|        * For the 'a' mode, we loop to handle all the modes. |  | ||||||
|        */ |  | ||||||
|       all_idx = -1; |       all_idx = -1; | ||||||
|       assert(modep < colonp); |       assert(modep < colonp); | ||||||
|       while (modep < colonp || all_idx >= 0) { |       while (modep < colonp || all_idx >= 0) { | ||||||
|         if (all_idx < 0) { |         if (all_idx < 0) { | ||||||
|           /* Find the mode. */ |           // Find the mode | ||||||
|           if (modep[1] == '-' || modep[1] == ':') |           if (modep[1] == '-' || modep[1] == ':') { | ||||||
|             len = 1; |             len = 1; | ||||||
|           else |           } else { | ||||||
|             len = 2; |             len = 2; | ||||||
|  |           } | ||||||
|  |  | ||||||
|           if (len == 1 && TOLOWER_ASC(modep[0]) == 'a') { |           if (len == 1 && TOLOWER_ASC(modep[0]) == 'a') { | ||||||
|             all_idx = SHAPE_IDX_COUNT - 1; |             all_idx = SHAPE_IDX_COUNT - 1; | ||||||
| @@ -100,11 +143,11 @@ char_u *parse_shape_opt(int what) | |||||||
|           modep += len + 1; |           modep += len + 1; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if (all_idx >= 0) |         if (all_idx >= 0) { | ||||||
|           idx = all_idx--; |           idx = all_idx--; | ||||||
|         else if (round == 2) { |         } else if (round == 2) { | ||||||
|           { |           { | ||||||
|             /* Set the defaults, for the missing parts */ |             // Set the defaults, for the missing parts | ||||||
|             shape_table[idx].shape = SHAPE_BLOCK; |             shape_table[idx].shape = SHAPE_BLOCK; | ||||||
|             shape_table[idx].blinkwait = 700L; |             shape_table[idx].blinkwait = 700L; | ||||||
|             shape_table[idx].blinkon = 400L; |             shape_table[idx].blinkon = 400L; | ||||||
| @@ -208,6 +251,23 @@ char_u *parse_shape_opt(int what) | |||||||
|       shape_table[SHAPE_IDX_VE].id_lm = shape_table[SHAPE_IDX_V].id_lm; |       shape_table[SHAPE_IDX_VE].id_lm = shape_table[SHAPE_IDX_V].id_lm; | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |   ui_cursor_style_set(); | ||||||
|   return NULL; |   return NULL; | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /// Map cursor mode from string to integer | ||||||
|  | /// | ||||||
|  | /// @param mode Fullname of the mode whose id we are looking for | ||||||
|  | /// @return -1 in case of failure, else the matching SHAPE_ID* integer | ||||||
|  | int cursor_mode_str2int(const char *mode) | ||||||
|  | { | ||||||
|  |   for (int current_mode = 0; current_mode < SHAPE_IDX_COUNT; current_mode++) { | ||||||
|  |     if (strcmp(shape_table[current_mode].full_name, mode) == 0) { | ||||||
|  |       return current_mode; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   ELOG("Unknown mode %s", mode); | ||||||
|  |   return -1; | ||||||
|  | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,32 +1,34 @@ | |||||||
| #ifndef NVIM_CURSOR_SHAPE_H | #ifndef NVIM_CURSOR_SHAPE_H | ||||||
| #define NVIM_CURSOR_SHAPE_H | #define NVIM_CURSOR_SHAPE_H | ||||||
|  |  | ||||||
| /* | /// struct to store values from 'guicursor' and 'mouseshape' | ||||||
|  * struct to store values from 'guicursor' and 'mouseshape' | /// Indexes in shape_table[] | ||||||
|  */ | typedef enum { | ||||||
| /* Indexes in shape_table[] */ | SHAPE_IDX_N      = 0,       ///< Normal mode | ||||||
| #define SHAPE_IDX_N     0       /* Normal mode */ | SHAPE_IDX_V      = 1,       ///< Visual mode | ||||||
| #define SHAPE_IDX_V     1       /* Visual mode */ | SHAPE_IDX_I      = 2,       ///< Insert mode | ||||||
| #define SHAPE_IDX_I     2       /* Insert mode */ | SHAPE_IDX_R      = 3,       ///< Replace mode | ||||||
| #define SHAPE_IDX_R     3       /* Replace mode */ | SHAPE_IDX_C      = 4,       ///< Command line Normal mode | ||||||
| #define SHAPE_IDX_C     4       /* Command line Normal mode */ | SHAPE_IDX_CI     = 5,       ///< Command line Insert mode | ||||||
| #define SHAPE_IDX_CI    5       /* Command line Insert mode */ | SHAPE_IDX_CR     = 6,       ///< Command line Replace mode | ||||||
| #define SHAPE_IDX_CR    6       /* Command line Replace mode */ | SHAPE_IDX_O      = 7,       ///< Operator-pending mode | ||||||
| #define SHAPE_IDX_O     7       /* Operator-pending mode */ | SHAPE_IDX_VE     = 8,       ///< Visual mode with 'selection' exclusive | ||||||
| #define SHAPE_IDX_VE    8       /* Visual mode with 'selection' exclusive */ | SHAPE_IDX_CLINE  = 9,       ///< On command line | ||||||
| #define SHAPE_IDX_CLINE 9       /* On command line */ | SHAPE_IDX_STATUS = 10,      ///<  status line | ||||||
| #define SHAPE_IDX_STATUS 10     /* A status line */ | SHAPE_IDX_SDRAG  = 11,      ///< dragging a status line | ||||||
| #define SHAPE_IDX_SDRAG 11      /* dragging a status line */ | SHAPE_IDX_VSEP   = 12,      ///< A vertical separator line | ||||||
| #define SHAPE_IDX_VSEP  12      /* A vertical separator line */ | SHAPE_IDX_VDRAG  = 13,      ///< dragging a vertical separator line | ||||||
| #define SHAPE_IDX_VDRAG 13      /* dragging a vertical separator line */ | SHAPE_IDX_MORE   = 14,      ///< Hit-return or More | ||||||
| #define SHAPE_IDX_MORE  14      /* Hit-return or More */ | SHAPE_IDX_MOREL  = 15,      ///< Hit-return or More in last line | ||||||
| #define SHAPE_IDX_MOREL 15      /* Hit-return or More in last line */ | SHAPE_IDX_SM     = 16,      ///< showing matching paren | ||||||
| #define SHAPE_IDX_SM    16      /* showing matching paren */ | SHAPE_IDX_COUNT  = 17 | ||||||
| #define SHAPE_IDX_COUNT 17 | } MouseMode; | ||||||
|  |  | ||||||
| #define SHAPE_BLOCK     0       /* block cursor */ | typedef enum { | ||||||
| #define SHAPE_HOR       1       /* horizontal bar cursor */ | SHAPE_BLOCK     = 0,       ///< block cursor | ||||||
| #define SHAPE_VER       2       /* vertical bar cursor */ | SHAPE_HOR       = 1,       ///< horizontal bar cursor | ||||||
|  | SHAPE_VER       = 2        ///< vertical bar cursor | ||||||
|  | } CursorShape; | ||||||
|  |  | ||||||
| #define MSHAPE_NUMBERED 1000    /* offset for shapes identified by number */ | #define MSHAPE_NUMBERED 1000    /* offset for shapes identified by number */ | ||||||
| #define MSHAPE_HIDE     1       /* hide mouse pointer */ | #define MSHAPE_HIDE     1       /* hide mouse pointer */ | ||||||
| @@ -35,16 +37,17 @@ | |||||||
| #define SHAPE_CURSOR    2       /* used for text cursor shape */ | #define SHAPE_CURSOR    2       /* used for text cursor shape */ | ||||||
|  |  | ||||||
| typedef struct cursor_entry { | typedef struct cursor_entry { | ||||||
|   int shape;                    /* one of the SHAPE_ defines */ |   char *full_name;        ///< mode full name | ||||||
|   int mshape;                   /* one of the MSHAPE defines */ |   CursorShape shape;      ///< cursor shape: one of the SHAPE_ defines | ||||||
|   int percentage;               /* percentage of cell for bar */ |   int mshape;             ///< mouse shape: one of the MSHAPE defines | ||||||
|   long blinkwait;               /* blinking, wait time before blinking starts */ |   int percentage;         ///< percentage of cell for bar | ||||||
|   long blinkon;                 /* blinking, on time */ |   long blinkwait;         ///< blinking, wait time before blinking starts | ||||||
|   long blinkoff;                /* blinking, off time */ |   long blinkon;           ///< blinking, on time | ||||||
|   int id;                       /* highlight group ID */ |   long blinkoff;          ///< blinking, off time | ||||||
|   int id_lm;                    /* highlight group ID for :lmap mode */ |   int id;                 ///< highlight group ID | ||||||
|   char        *name;            /* mode name (fixed) */ |   int id_lm;              ///< highlight group ID for :lmap mode | ||||||
|   char used_for;                /* SHAPE_MOUSE and/or SHAPE_CURSOR */ |   char *name;             ///< mode short name | ||||||
|  |   char used_for;          ///< SHAPE_MOUSE and/or SHAPE_CURSOR | ||||||
| } cursorentry_T; | } cursorentry_T; | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -42,29 +42,29 @@ | |||||||
|  |  | ||||||
| static bool did_syntax_onoff = false; | static bool did_syntax_onoff = false; | ||||||
|  |  | ||||||
| // Structure that stores information about a highlight group. | /// Structure that stores information about a highlight group. | ||||||
| // The ID of a highlight group is also called group ID.  It is the index in | /// The ID of a highlight group is also called group ID.  It is the index in | ||||||
| // the highlight_ga array PLUS ONE. | /// the highlight_ga array PLUS ONE. | ||||||
| struct hl_group { | struct hl_group { | ||||||
|   char_u      *sg_name;         // highlight group name |   char_u      *sg_name;         ///< highlight group name | ||||||
|   char_u      *sg_name_u;       // uppercase of sg_name |   char_u      *sg_name_u;       ///< uppercase of sg_name | ||||||
|   int sg_attr;                  // Screen attr |   int sg_attr;                  ///< Screen attr | ||||||
|   int sg_link;                  // link to this highlight group ID |   int sg_link;                  ///< link to this highlight group ID | ||||||
|   int sg_set;                   // combination of SG_* flags |   int sg_set;                   ///< combination of SG_* flags | ||||||
|   scid_T sg_scriptID;           // script in which the group was last set |   scid_T sg_scriptID;           ///< script in which the group was last set | ||||||
|   // for terminal UIs |   // for terminal UIs | ||||||
|   int sg_cterm;                 // "cterm=" highlighting attr |   int sg_cterm;                 ///< "cterm=" highlighting attr | ||||||
|   int sg_cterm_fg;              // terminal fg color number + 1 |   int sg_cterm_fg;              ///< terminal fg color number + 1 | ||||||
|   int sg_cterm_bg;              // terminal bg color number + 1 |   int sg_cterm_bg;              ///< terminal bg color number + 1 | ||||||
|   int sg_cterm_bold;            // bold attr was set for light color |   int sg_cterm_bold;            ///< bold attr was set for light color | ||||||
|   // for RGB UIs |   // for RGB UIs | ||||||
|   int sg_gui;                   // "gui=" highlighting attributes |   int sg_gui;                   ///< "gui=" highlighting attributes | ||||||
|   RgbValue sg_rgb_fg;           // RGB foreground color |   RgbValue sg_rgb_fg;           ///< RGB foreground color | ||||||
|   RgbValue sg_rgb_bg;           // RGB background color |   RgbValue sg_rgb_bg;           ///< RGB background color | ||||||
|   RgbValue sg_rgb_sp;           // RGB special color |   RgbValue sg_rgb_sp;           ///< RGB special color | ||||||
|   uint8_t *sg_rgb_fg_name;      // RGB foreground color name |   uint8_t *sg_rgb_fg_name;      ///< RGB foreground color name | ||||||
|   uint8_t *sg_rgb_bg_name;      // RGB background color name |   uint8_t *sg_rgb_bg_name;      ///< RGB background color name | ||||||
|   uint8_t *sg_rgb_sp_name;      // RGB special color name |   uint8_t *sg_rgb_sp_name;      ///< RGB special color name | ||||||
| }; | }; | ||||||
|  |  | ||||||
| #define SG_CTERM        2       // cterm has been set | #define SG_CTERM        2       // cterm has been set | ||||||
| @@ -7165,12 +7165,13 @@ int syn_namen2id(char_u *linep, int len) | |||||||
|   return id; |   return id; | ||||||
| } | } | ||||||
|  |  | ||||||
| /* | /// Find highlight group name in the table and return it's ID. | ||||||
|  * Find highlight group name in the table and return it's ID. | /// If it doesn't exist yet, a new entry is created. | ||||||
|  * The argument is a pointer to the name and the length of the name. | /// | ||||||
|  * If it doesn't exist yet, a new entry is created. | /// @param pp Highlight group name | ||||||
|  * Return 0 for failure. | /// @param len length of \p pp | ||||||
|  */ | /// | ||||||
|  | /// @return 0 for failure else the id of the group | ||||||
| int syn_check_group(char_u *pp, int len) | int syn_check_group(char_u *pp, int len) | ||||||
| { | { | ||||||
|   char_u  *name = vim_strnsave(pp, len); |   char_u  *name = vim_strnsave(pp, len); | ||||||
|   | |||||||
| @@ -31,6 +31,8 @@ | |||||||
| #include "nvim/ugrid.h" | #include "nvim/ugrid.h" | ||||||
| #include "nvim/tui/input.h" | #include "nvim/tui/input.h" | ||||||
| #include "nvim/tui/tui.h" | #include "nvim/tui/tui.h" | ||||||
|  | #include "nvim/cursor_shape.h" | ||||||
|  | #include "nvim/syntax.h" | ||||||
|  |  | ||||||
| // Space reserved in the output buffer to restore the cursor to normal when | // Space reserved in the output buffer to restore the cursor to normal when | ||||||
| // flushing. No existing terminal will require 32 bytes to do that. | // flushing. No existing terminal will require 32 bytes to do that. | ||||||
| @@ -69,12 +71,12 @@ typedef struct { | |||||||
|   bool can_use_terminal_scroll; |   bool can_use_terminal_scroll; | ||||||
|   bool mouse_enabled; |   bool mouse_enabled; | ||||||
|   bool busy; |   bool busy; | ||||||
|  |   cursorentry_T cursor_shapes[SHAPE_IDX_COUNT]; | ||||||
|   HlAttrs print_attrs; |   HlAttrs print_attrs; | ||||||
|   int showing_mode; |   int showing_mode; | ||||||
|   struct { |   struct { | ||||||
|     int enable_mouse, disable_mouse; |     int enable_mouse, disable_mouse; | ||||||
|     int enable_bracketed_paste, disable_bracketed_paste; |     int enable_bracketed_paste, disable_bracketed_paste; | ||||||
|     int set_cursor_shape_bar, set_cursor_shape_ul, set_cursor_shape_block; |  | ||||||
|     int set_rgb_foreground, set_rgb_background; |     int set_rgb_foreground, set_rgb_background; | ||||||
|     int enable_focus_reporting, disable_focus_reporting; |     int enable_focus_reporting, disable_focus_reporting; | ||||||
|   } unibi_ext; |   } unibi_ext; | ||||||
| @@ -97,6 +99,7 @@ UI *tui_start(void) | |||||||
|   ui->clear = tui_clear; |   ui->clear = tui_clear; | ||||||
|   ui->eol_clear = tui_eol_clear; |   ui->eol_clear = tui_eol_clear; | ||||||
|   ui->cursor_goto = tui_cursor_goto; |   ui->cursor_goto = tui_cursor_goto; | ||||||
|  |   ui->cursor_style_set = tui_cursor_style_set; | ||||||
|   ui->update_menu = tui_update_menu; |   ui->update_menu = tui_update_menu; | ||||||
|   ui->busy_start = tui_busy_start; |   ui->busy_start = tui_busy_start; | ||||||
|   ui->busy_stop = tui_busy_stop; |   ui->busy_stop = tui_busy_stop; | ||||||
| @@ -131,9 +134,6 @@ static void terminfo_start(UI *ui) | |||||||
|   data->unibi_ext.disable_mouse = -1; |   data->unibi_ext.disable_mouse = -1; | ||||||
|   data->unibi_ext.enable_bracketed_paste = -1; |   data->unibi_ext.enable_bracketed_paste = -1; | ||||||
|   data->unibi_ext.disable_bracketed_paste = -1; |   data->unibi_ext.disable_bracketed_paste = -1; | ||||||
|   data->unibi_ext.set_cursor_shape_bar = -1; |  | ||||||
|   data->unibi_ext.set_cursor_shape_ul = -1; |  | ||||||
|   data->unibi_ext.set_cursor_shape_block = -1; |  | ||||||
|   data->unibi_ext.enable_focus_reporting = -1; |   data->unibi_ext.enable_focus_reporting = -1; | ||||||
|   data->unibi_ext.disable_focus_reporting = -1; |   data->unibi_ext.disable_focus_reporting = -1; | ||||||
|   data->out_fd = 1; |   data->out_fd = 1; | ||||||
| @@ -147,7 +147,6 @@ static void terminfo_start(UI *ui) | |||||||
|   } |   } | ||||||
|   fix_terminfo(data); |   fix_terminfo(data); | ||||||
|   // Initialize the cursor shape. |   // Initialize the cursor shape. | ||||||
|   unibi_out(ui, data->unibi_ext.set_cursor_shape_block); |  | ||||||
|   // Set 't_Co' from the result of unibilium & fix_terminfo. |   // Set 't_Co' from the result of unibilium & fix_terminfo. | ||||||
|   t_colors = unibi_get_num(data->ut, unibi_max_colors); |   t_colors = unibi_get_num(data->ut, unibi_max_colors); | ||||||
|   // Enter alternate screen and clear |   // Enter alternate screen and clear | ||||||
| @@ -434,6 +433,64 @@ static void tui_cursor_goto(UI *ui, int row, int col) | |||||||
|   unibi_goto(ui, row, col); |   unibi_goto(ui, row, col); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | CursorShape tui_cursor_decode_shape(const char *shape_str) | ||||||
|  | { | ||||||
|  |   CursorShape shape = 0; | ||||||
|  |   if (strcmp(shape_str, "block") == 0) { | ||||||
|  |     shape = SHAPE_BLOCK; | ||||||
|  |   } else if (strcmp(shape_str, "vertical") == 0) { | ||||||
|  |     shape = SHAPE_VER; | ||||||
|  |   } else if (strcmp(shape_str, "horizontal") == 0) { | ||||||
|  |     shape = SHAPE_HOR; | ||||||
|  |   } else { | ||||||
|  |     EMSG2(_(e_invarg2), shape_str); | ||||||
|  |   } | ||||||
|  |   return shape; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static cursorentry_T decode_cursor_entry(Dictionary args) | ||||||
|  | { | ||||||
|  |   cursorentry_T r; | ||||||
|  |  | ||||||
|  |   for (size_t i = 0; i < args.size; i++) { | ||||||
|  |     char *keyStr = args.items[i].key.data; | ||||||
|  |     Object value = args.items[i].value; | ||||||
|  |  | ||||||
|  |     if (strcmp(keyStr, "cursor_shape") == 0) { | ||||||
|  |       r.shape = tui_cursor_decode_shape(args.items[i].value.data.string.data); | ||||||
|  |     } else if (strcmp(keyStr, "blinkon") == 0) { | ||||||
|  |       r.blinkon = (int)value.data.integer; | ||||||
|  |     } else if (strcmp(keyStr, "blinkoff") == 0) { | ||||||
|  |       r.blinkoff = (int)value.data.integer; | ||||||
|  |     } else if (strcmp(keyStr, "hl_id") == 0) { | ||||||
|  |       r.id = (int)value.data.integer; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   return r; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void tui_cursor_style_set(UI *ui, Dictionary args) | ||||||
|  | { | ||||||
|  |   TUIData *data = ui->data; | ||||||
|  |  | ||||||
|  |   for (size_t i = 0; i < args.size; i++) { | ||||||
|  |     char *mode_name = args.items[i].key.data; | ||||||
|  |     const int mode_id = cursor_mode_str2int(mode_name); | ||||||
|  |  | ||||||
|  |     if (mode_id < 0) { | ||||||
|  |       WLOG("Unknown mode '%s'", mode_name); | ||||||
|  |       continue; | ||||||
|  |     } | ||||||
|  |     cursorentry_T r = decode_cursor_entry(args.items[i].value.data.dictionary); | ||||||
|  |     r.full_name = mode_name; | ||||||
|  |     data->cursor_shapes[mode_id] = r; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // force redrawal | ||||||
|  |   MouseMode cursor_mode = tui_mode2cursor(data->showing_mode); | ||||||
|  |   tui_set_cursor(ui, cursor_mode); | ||||||
|  | } | ||||||
|  |  | ||||||
| static void tui_update_menu(UI *ui) | static void tui_update_menu(UI *ui) | ||||||
| { | { | ||||||
|     // Do nothing; menus are for GUI only |     // Do nothing; menus are for GUI only | ||||||
| @@ -467,26 +524,83 @@ static void tui_mouse_off(UI *ui) | |||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /// @param mode one of SHAPE_XXX | ||||||
|  | static void tui_set_cursor(UI *ui, MouseMode mode) | ||||||
|  | { | ||||||
|  |   TUIData *data = ui->data; | ||||||
|  |   cursorentry_T c = data->cursor_shapes[mode]; | ||||||
|  |   int shape = c.shape; | ||||||
|  |   bool inside_tmux = os_getenv("TMUX") != NULL; | ||||||
|  |   unibi_var_t vars[26 + 26] = { { 0 } }; | ||||||
|  |  | ||||||
|  | # define TMUX_WRAP(seq) (inside_tmux ? "\x1bPtmux;\x1b" seq "\x1b\\" : seq) | ||||||
|  |   // Support changing cursor shape on some popular terminals. | ||||||
|  |   const char *term_prog = os_getenv("TERM_PROGRAM"); | ||||||
|  |   const char *vte_version = os_getenv("VTE_VERSION"); | ||||||
|  |  | ||||||
|  |   if ((term_prog && !strcmp(term_prog, "Konsole")) | ||||||
|  |       || os_getenv("KONSOLE_DBUS_SESSION") != NULL) { | ||||||
|  |     // Konsole uses a proprietary escape code to set the cursor shape | ||||||
|  |     // and does not support DECSCUSR. | ||||||
|  |     switch (shape) { | ||||||
|  |       case SHAPE_BLOCK: shape = 0; break; | ||||||
|  |       case SHAPE_VER:   shape = 1; break; | ||||||
|  |       case SHAPE_HOR:   shape = 3; break; | ||||||
|  |       default: WLOG("Unknown shape value %d", shape); break; | ||||||
|  |     } | ||||||
|  |     printf(TMUX_WRAP("\x1b]50;CursorShape=%d;BlinkingCursorEnabled=%d\x07"), | ||||||
|  |            shape, (c.blinkon !=0)); | ||||||
|  |   } else if (!vte_version || atoi(vte_version) >= 3900) { | ||||||
|  |     // Assume that the terminal supports DECSCUSR unless it is an | ||||||
|  |     // old VTE based terminal.  This should not get wrapped for tmux, | ||||||
|  |     // which will handle it via its Ss/Se terminfo extension - usually | ||||||
|  |     // according to its terminal-overrides. | ||||||
|  |  | ||||||
|  |     switch (shape) { | ||||||
|  |       case SHAPE_BLOCK: shape = 1; break; | ||||||
|  |       case SHAPE_VER:   shape = 5; break; | ||||||
|  |       case SHAPE_HOR:   shape = 3; break; | ||||||
|  |       default: WLOG("Unknown shape value %d", shape); break; | ||||||
|  |     } | ||||||
|  |     data->params[0].i = shape + (c.blinkon ==0); | ||||||
|  |     unibi_format(vars, vars + 26, "\x1b[%p1%d q", | ||||||
|  |                  data->params, out, ui, NULL, NULL); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /// Returns cursor mode from edit mode | ||||||
|  | static MouseMode tui_mode2cursor(int mode) | ||||||
|  | { | ||||||
|  |   switch (mode) { | ||||||
|  |     case INSERT:  return SHAPE_IDX_I; | ||||||
|  |     case CMDLINE: return SHAPE_IDX_C; | ||||||
|  |     case REPLACE: return SHAPE_IDX_R; | ||||||
|  |     case NORMAL: | ||||||
|  |     default:      return SHAPE_IDX_N; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /// @param mode editor mode | ||||||
| static void tui_mode_change(UI *ui, int mode) | static void tui_mode_change(UI *ui, int mode) | ||||||
| { | { | ||||||
|   TUIData *data = ui->data; |   TUIData *data = ui->data; | ||||||
|  |  | ||||||
|   if (mode == INSERT) { |   if (mode == INSERT) { | ||||||
|     if (data->showing_mode != INSERT) { |     if (data->showing_mode != INSERT) { | ||||||
|       unibi_out(ui, data->unibi_ext.set_cursor_shape_bar); |       tui_set_cursor(ui, SHAPE_IDX_I); | ||||||
|     } |     } | ||||||
|   } else if (mode == CMDLINE) { |   } else if (mode == CMDLINE) { | ||||||
|     if (data->showing_mode != CMDLINE) { |     if (data->showing_mode != CMDLINE) { | ||||||
|       unibi_out(ui, data->unibi_ext.set_cursor_shape_bar); |       tui_set_cursor(ui, SHAPE_IDX_C); | ||||||
|     } |     } | ||||||
|   } else if (mode == REPLACE) { |   } else if (mode == REPLACE) { | ||||||
|     if (data->showing_mode != REPLACE) { |     if (data->showing_mode != REPLACE) { | ||||||
|       unibi_out(ui, data->unibi_ext.set_cursor_shape_ul); |       tui_set_cursor(ui, SHAPE_IDX_R); | ||||||
|     } |     } | ||||||
|   } else { |   } else { | ||||||
|     assert(mode == NORMAL); |     assert(mode == NORMAL); | ||||||
|     if (data->showing_mode != NORMAL) { |     if (data->showing_mode != NORMAL) { | ||||||
|       unibi_out(ui, data->unibi_ext.set_cursor_shape_block); |       tui_set_cursor(ui, SHAPE_IDX_N); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|   data->showing_mode = mode; |   data->showing_mode = mode; | ||||||
| @@ -831,8 +945,6 @@ static void fix_terminfo(TUIData *data) | |||||||
|     goto end; |     goto end; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   bool inside_tmux = os_getenv("TMUX") != NULL; |  | ||||||
|  |  | ||||||
| #define STARTS_WITH(str, prefix) (!memcmp(str, prefix, sizeof(prefix) - 1)) | #define STARTS_WITH(str, prefix) (!memcmp(str, prefix, sizeof(prefix) - 1)) | ||||||
|  |  | ||||||
|   if (STARTS_WITH(term, "rxvt")) { |   if (STARTS_WITH(term, "rxvt")) { | ||||||
| @@ -890,40 +1002,6 @@ static void fix_terminfo(TUIData *data) | |||||||
|     unibi_set_str(ut, unibi_set_a_background, XTERM_SETAB); |     unibi_set_str(ut, unibi_set_a_background, XTERM_SETAB); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   const char * env_cusr_shape = os_getenv("NVIM_TUI_ENABLE_CURSOR_SHAPE"); |  | ||||||
|   if (env_cusr_shape && strncmp(env_cusr_shape, "0", 1) == 0) { |  | ||||||
|     goto end; |  | ||||||
|   } |  | ||||||
|   bool cusr_blink = env_cusr_shape && strncmp(env_cusr_shape, "2", 1) == 0; |  | ||||||
|  |  | ||||||
| #define TMUX_WRAP(seq) (inside_tmux ? "\x1bPtmux;\x1b" seq "\x1b\\" : seq) |  | ||||||
|   // Support changing cursor shape on some popular terminals. |  | ||||||
|   const char *term_prog = os_getenv("TERM_PROGRAM"); |  | ||||||
|   const char *vte_version = os_getenv("VTE_VERSION"); |  | ||||||
|  |  | ||||||
|   if ((term_prog && !strcmp(term_prog, "Konsole")) |  | ||||||
|       || os_getenv("KONSOLE_DBUS_SESSION") != NULL) { |  | ||||||
|     // Konsole uses a proprietary escape code to set the cursor shape |  | ||||||
|     // and does not support DECSCUSR. |  | ||||||
|     data->unibi_ext.set_cursor_shape_bar = (int)unibi_add_ext_str(ut, NULL, |  | ||||||
|         TMUX_WRAP("\x1b]50;CursorShape=1\x07")); |  | ||||||
|     data->unibi_ext.set_cursor_shape_ul = (int)unibi_add_ext_str(ut, NULL, |  | ||||||
|         TMUX_WRAP("\x1b]50;CursorShape=2\x07")); |  | ||||||
|     data->unibi_ext.set_cursor_shape_block = (int)unibi_add_ext_str(ut, NULL, |  | ||||||
|         TMUX_WRAP("\x1b]50;CursorShape=0\x07")); |  | ||||||
|   } else if (!vte_version || atoi(vte_version) >= 3900) { |  | ||||||
|     // Assume that the terminal supports DECSCUSR unless it is an |  | ||||||
|     // old VTE based terminal.  This should not get wrapped for tmux, |  | ||||||
|     // which will handle it via its Ss/Se terminfo extension - usually |  | ||||||
|     // according to its terminal-overrides. |  | ||||||
|     data->unibi_ext.set_cursor_shape_bar = |  | ||||||
|       (int)unibi_add_ext_str(ut, NULL, cusr_blink ? "\x1b[5 q" : "\x1b[6 q"); |  | ||||||
|     data->unibi_ext.set_cursor_shape_ul = |  | ||||||
|       (int)unibi_add_ext_str(ut, NULL, cusr_blink ? "\x1b[3 q" : "\x1b[4 q"); |  | ||||||
|     data->unibi_ext.set_cursor_shape_block = |  | ||||||
|       (int)unibi_add_ext_str(ut, NULL, cusr_blink ? "\x1b[1 q" : "\x1b[2 q"); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
| end: | end: | ||||||
|   // Fill some empty slots with common terminal strings |   // Fill some empty slots with common terminal strings | ||||||
|   data->unibi_ext.enable_mouse = (int)unibi_add_ext_str(ut, NULL, |   data->unibi_ext.enable_mouse = (int)unibi_add_ext_str(ut, NULL, | ||||||
|   | |||||||
| @@ -1,6 +1,8 @@ | |||||||
| #ifndef NVIM_TUI_TUI_H | #ifndef NVIM_TUI_TUI_H | ||||||
| #define NVIM_TUI_TUI_H | #define NVIM_TUI_TUI_H | ||||||
|  |  | ||||||
|  | #include "nvim/cursor_shape.h" | ||||||
|  |  | ||||||
| #ifdef INCLUDE_GENERATED_DECLARATIONS | #ifdef INCLUDE_GENERATED_DECLARATIONS | ||||||
| # include "tui/tui.h.generated.h" | # include "tui/tui.h.generated.h" | ||||||
| #endif | #endif | ||||||
|   | |||||||
| @@ -29,6 +29,7 @@ | |||||||
| #include "nvim/screen.h" | #include "nvim/screen.h" | ||||||
| #include "nvim/syntax.h" | #include "nvim/syntax.h" | ||||||
| #include "nvim/window.h" | #include "nvim/window.h" | ||||||
|  | #include "nvim/cursor_shape.h" | ||||||
| #ifdef FEAT_TUI | #ifdef FEAT_TUI | ||||||
| # include "nvim/tui/tui.h" | # include "nvim/tui/tui.h" | ||||||
| #else | #else | ||||||
| @@ -179,6 +180,7 @@ void ui_refresh(void) | |||||||
|   row = col = 0; |   row = col = 0; | ||||||
|   screen_resize(width, height); |   screen_resize(width, height); | ||||||
|   pum_set_external(pum_external); |   pum_set_external(pum_external); | ||||||
|  |   ui_cursor_style_set(); | ||||||
| } | } | ||||||
|  |  | ||||||
| static void ui_refresh_event(void **argv) | static void ui_refresh_event(void **argv) | ||||||
| @@ -376,6 +378,13 @@ void ui_cursor_goto(int new_row, int new_col) | |||||||
|   pending_cursor_update = true; |   pending_cursor_update = true; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | void ui_cursor_style_set(void) | ||||||
|  | { | ||||||
|  |   Dictionary style = cursor_shape_dict(); | ||||||
|  |   UI_CALL(cursor_style_set, style); | ||||||
|  |   api_free_dictionary(style); | ||||||
|  | } | ||||||
|  |  | ||||||
| void ui_update_menu(void) | void ui_update_menu(void) | ||||||
| { | { | ||||||
|     UI_CALL(update_menu); |     UI_CALL(update_menu); | ||||||
|   | |||||||
| @@ -22,6 +22,7 @@ struct ui_t { | |||||||
|   void (*clear)(UI *ui); |   void (*clear)(UI *ui); | ||||||
|   void (*eol_clear)(UI *ui); |   void (*eol_clear)(UI *ui); | ||||||
|   void (*cursor_goto)(UI *ui, int row, int col); |   void (*cursor_goto)(UI *ui, int row, int col); | ||||||
|  |   void (*cursor_style_set)(UI *ui, Dictionary cursor_shapes); | ||||||
|   void (*update_menu)(UI *ui); |   void (*update_menu)(UI *ui); | ||||||
|   void (*busy_start)(UI *ui); |   void (*busy_start)(UI *ui); | ||||||
|   void (*busy_stop)(UI *ui); |   void (*busy_stop)(UI *ui); | ||||||
|   | |||||||
| @@ -13,6 +13,7 @@ | |||||||
| #include "nvim/memory.h" | #include "nvim/memory.h" | ||||||
| #include "nvim/ui_bridge.h" | #include "nvim/ui_bridge.h" | ||||||
| #include "nvim/ugrid.h" | #include "nvim/ugrid.h" | ||||||
|  | #include "nvim/api/private/helpers.h" | ||||||
|  |  | ||||||
| #ifdef INCLUDE_GENERATED_DECLARATIONS | #ifdef INCLUDE_GENERATED_DECLARATIONS | ||||||
| # include "ui_bridge.c.generated.h" | # include "ui_bridge.c.generated.h" | ||||||
| @@ -59,6 +60,7 @@ UI *ui_bridge_attach(UI *ui, ui_main_fn ui_main, event_scheduler scheduler) | |||||||
|   rv->bridge.clear = ui_bridge_clear; |   rv->bridge.clear = ui_bridge_clear; | ||||||
|   rv->bridge.eol_clear = ui_bridge_eol_clear; |   rv->bridge.eol_clear = ui_bridge_eol_clear; | ||||||
|   rv->bridge.cursor_goto = ui_bridge_cursor_goto; |   rv->bridge.cursor_goto = ui_bridge_cursor_goto; | ||||||
|  |   rv->bridge.cursor_style_set = ui_bridge_cursor_styleset; | ||||||
|   rv->bridge.update_menu = ui_bridge_update_menu; |   rv->bridge.update_menu = ui_bridge_update_menu; | ||||||
|   rv->bridge.busy_start = ui_bridge_busy_start; |   rv->bridge.busy_start = ui_bridge_busy_start; | ||||||
|   rv->bridge.busy_stop = ui_bridge_busy_stop; |   rv->bridge.busy_stop = ui_bridge_busy_stop; | ||||||
| @@ -178,6 +180,23 @@ static void ui_bridge_cursor_goto_event(void **argv) | |||||||
|   ui->cursor_goto(ui, PTR2INT(argv[1]), PTR2INT(argv[2])); |   ui->cursor_goto(ui, PTR2INT(argv[1]), PTR2INT(argv[2])); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | static void ui_bridge_cursor_styleset(UI *b, Dictionary style) | ||||||
|  | { | ||||||
|  |   Object copy = copy_object(DICTIONARY_OBJ(style)); | ||||||
|  |   Object *pobj = xmalloc(sizeof(copy)); | ||||||
|  |   *pobj = copy; | ||||||
|  |   UI_CALL(b, cursor_styleset, 2, b, pobj); | ||||||
|  | } | ||||||
|  | static void ui_bridge_cursor_styleset_event(void **argv) | ||||||
|  | { | ||||||
|  |   UI *ui = UI(argv[0]); | ||||||
|  |   Object *styles = (Object *)argv[1]; | ||||||
|  |  | ||||||
|  |   ui->cursor_style_set(ui, styles->data.dictionary); | ||||||
|  |   api_free_object(*styles); | ||||||
|  |   xfree(styles); | ||||||
|  | } | ||||||
|  |  | ||||||
| static void ui_bridge_update_menu(UI *b) | static void ui_bridge_update_menu(UI *b) | ||||||
| { | { | ||||||
|   UI_CALL(b, update_menu, 1, b); |   UI_CALL(b, update_menu, 1, b); | ||||||
|   | |||||||
| @@ -313,6 +313,8 @@ function Screen:_redraw(updates) | |||||||
|       if handler ~= nil then |       if handler ~= nil then | ||||||
|         handler(self, unpack(update[i])) |         handler(self, unpack(update[i])) | ||||||
|       else |       else | ||||||
|  |         assert(self._on_event, "Either add an Screen:_handle_XXX method ".. | ||||||
|  |                " or call Screen:set_on_event_handler") | ||||||
|         self._on_event(method, update[i]) |         self._on_event(method, update[i]) | ||||||
|       end |       end | ||||||
|     end |     end | ||||||
| @@ -343,6 +345,10 @@ function Screen:_handle_resize(width, height) | |||||||
|   } |   } | ||||||
| end | end | ||||||
|  |  | ||||||
|  | function Screen:_handle_cursor_style_set(styles) | ||||||
|  |   self._cursor_styles = styles | ||||||
|  | end | ||||||
|  |  | ||||||
| function Screen:_handle_clear() | function Screen:_handle_clear() | ||||||
|   self:_clear_block(self._scroll_region.top, self._scroll_region.bot, |   self:_clear_block(self._scroll_region.top, self._scroll_region.bot, | ||||||
|                     self._scroll_region.left, self._scroll_region.right) |                     self._scroll_region.left, self._scroll_region.right) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user