diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/nvim/api/ui.c | 10 | ||||
| -rw-r--r-- | src/nvim/cursor_shape.c | 137 | ||||
| -rw-r--r-- | src/nvim/cursor_shape.h | 73 | ||||
| -rw-r--r-- | src/nvim/options.lua | 2 | ||||
| -rw-r--r-- | src/nvim/syntax.c | 94 | ||||
| -rw-r--r-- | src/nvim/syntax.h | 10 | ||||
| -rw-r--r-- | src/nvim/tui/tui.c | 186 | ||||
| -rw-r--r-- | src/nvim/tui/tui.h | 2 | ||||
| -rw-r--r-- | src/nvim/ui.c | 9 | ||||
| -rw-r--r-- | src/nvim/ui.h | 1 | ||||
| -rw-r--r-- | src/nvim/ui_bridge.c | 19 | 
11 files changed, 371 insertions, 172 deletions
| diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c index 625bcc6b4b..a95be0fabb 100644 --- a/src/nvim/api/ui.c +++ b/src/nvim/api/ui.c @@ -12,6 +12,7 @@  #include "nvim/api/private/defs.h"  #include "nvim/api/private/helpers.h"  #include "nvim/popupmnu.h" +#include "nvim/cursor_shape.h"  #ifdef INCLUDE_GENERATED_DECLARATIONS  # 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->eol_clear = remote_ui_eol_clear;    ui->cursor_goto = remote_ui_cursor_goto; +  ui->cursor_style_set = remote_ui_cursor_style_set;    ui->update_menu = remote_ui_update_menu;    ui->busy_start = remote_ui_busy_start;    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);  } +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)  {    Array args = ARRAY_DICT_INIT; diff --git a/src/nvim/cursor_shape.c b/src/nvim/cursor_shape.c index b50462664c..7ec70bb724 100644 --- a/src/nvim/cursor_shape.c +++ b/src/nvim/cursor_shape.c @@ -7,40 +7,74 @@  #include "nvim/charset.h"  #include "nvim/strings.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] =  { -  /* The values will be filled in from the 'guicursor' and 'mouseshape' -   * defaults when Vim starts. -   * Adjust the SHAPE_IDX_ defines when making changes! */ -  {0, 0, 0, 700L, 400L, 250L, 0, 0, "n", 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, "i", 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, "c", SHAPE_CURSOR+SHAPE_MOUSE}, -  {0, 0, 0, 700L, 400L, 250L, 0, 0, "ci", SHAPE_CURSOR+SHAPE_MOUSE}, -  {0, 0, 0, 700L, 400L, 250L, 0, 0, "cr", SHAPE_CURSOR+SHAPE_MOUSE}, -  {0, 0, 0, 700L, 400L, 250L, 0, 0, "o", SHAPE_CURSOR+SHAPE_MOUSE}, -  {0, 0, 0, 700L, 400L, 250L, 0, 0, "ve", SHAPE_CURSOR+SHAPE_MOUSE}, -  {0, 0, 0,   0L,   0L,   0L, 0, 0, "e", SHAPE_MOUSE}, -  {0, 0, 0,   0L,   0L,   0L, 0, 0, "s", SHAPE_MOUSE}, -  {0, 0, 0,   0L,   0L,   0L, 0, 0, "sd", SHAPE_MOUSE}, -  {0, 0, 0,   0L,   0L,   0L, 0, 0, "vs", SHAPE_MOUSE}, -  {0, 0, 0,   0L,   0L,   0L, 0, 0, "vd", SHAPE_MOUSE}, -  {0, 0, 0,   0L,   0L,   0L, 0, 0, "m", SHAPE_MOUSE}, -  {0, 0, 0,   0L,   0L,   0L, 0, 0, "ml", SHAPE_MOUSE}, -  {0, 0, 0, 100L, 100L, 100L, 0, 0, "sm", SHAPE_CURSOR}, +  // Values are set by 'guicursor' and 'mouseshape'. +  // Adjust the SHAPE_IDX_ defines when changing this! +  { "normal", 0, 0, 0, 700L, 400L, 250L, 0, 0, "n", SHAPE_CURSOR+SHAPE_MOUSE }, +  { "visual", 0, 0, 0, 700L, 400L, 250L, 0, 0, "v", SHAPE_CURSOR+SHAPE_MOUSE }, +  { "insert", 0, 0, 0, 700L, 400L, 250L, 0, 0, "i", SHAPE_CURSOR+SHAPE_MOUSE }, +  { "replace", 0, 0, 0, 700L, 400L, 250L, 0, 0, "r", SHAPE_CURSOR+SHAPE_MOUSE }, +  { "cmdline_normal", 0, 0, 0, 700L, 400L, 250L, 0, 0, "c", SHAPE_CURSOR+SHAPE_MOUSE }, +  { "cmdline_insert", 0, 0, 0, 700L, 400L, 250L, 0, 0, "ci", SHAPE_CURSOR+SHAPE_MOUSE }, +  { "cmdline_replace", 0, 0, 0, 700L, 400L, 250L, 0, 0, "cr", SHAPE_CURSOR+SHAPE_MOUSE }, +  { "operator", 0, 0, 0, 700L, 400L, 250L, 0, 0, "o", SHAPE_CURSOR+SHAPE_MOUSE }, +  { "visual_select", 0, 0, 0, 700L, 400L, 250L, 0, 0, "ve", SHAPE_CURSOR+SHAPE_MOUSE }, +  { "cmdline_hover", 0, 0, 0,   0L,   0L,   0L, 0, 0, "e", SHAPE_MOUSE }, +  { "statusline_hover", 0, 0, 0,   0L,   0L,   0L, 0, 0, "s", SHAPE_MOUSE }, +  { "statusline_drag", 0, 0, 0,   0L,   0L,   0L, 0, 0, "sd", SHAPE_MOUSE }, +  { "vsep_hover", 0, 0, 0,   0L,   0L,   0L, 0, 0, "vs", SHAPE_MOUSE }, +  { "vsep_drag", 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 }, +  { "showmatch", 0, 0, 0, 100L, 100L, 100L, 0, 0, "sm", SHAPE_CURSOR },  }; -/* - * Parse the 'guicursor' option ("what" is SHAPE_CURSOR) or 'mouseshape' - * ("what" is SHAPE_MOUSE). - * Returns error message for an illegal option, NULL otherwise. - */ +/// Converts cursor_shapes into a Dictionary of dictionaries +/// @return dictionary of the form {"normal" : { "cursor_shape": ... }, ...} +Dictionary cursor_shape_dict(void) +{ +  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 SHAPE_CURSOR or SHAPE_MOUSE ('mouseshape') +/// +/// @returns error message for an illegal option, NULL otherwise.  char_u *parse_shape_opt(int what)  {    char_u      *modep; @@ -59,10 +93,11 @@ char_u *parse_shape_opt(int what)     * First round: check for errors; second round: do it for real.     */    for (round = 1; round <= 2; ++round) { -    /* -     * Repeat for all comma separated parts. -     */ +    // Repeat for all comma separated parts.      modep = p_guicursor; +    if (*p_guicursor == NUL) { +      modep = (char_u *)"a:block-blinkon0"; +    }      while (*modep != NUL) {        colonp = vim_strchr(modep, ':');        if (colonp == NULL) @@ -71,19 +106,18 @@ char_u *parse_shape_opt(int what)          return (char_u *)N_("E546: Illegal mode");        commap = vim_strchr(modep, ','); -      /* -       * Repeat for all mode's before the colon. -       * For the 'a' mode, we loop to handle all the modes. -       */ +      // Repeat for all modes before the colon. +      // For the 'a' mode, we loop to handle all the modes.        all_idx = -1;        assert(modep < colonp);        while (modep < colonp || all_idx >= 0) {          if (all_idx < 0) { -          /* Find the mode. */ -          if (modep[1] == '-' || modep[1] == ':') +          // Find the mode +          if (modep[1] == '-' || modep[1] == ':') {              len = 1; -          else +          } else {              len = 2; +          }            if (len == 1 && TOLOWER_ASC(modep[0]) == 'a') {              all_idx = SHAPE_IDX_COUNT - 1; @@ -100,11 +134,11 @@ char_u *parse_shape_opt(int what)            modep += len + 1;          } -        if (all_idx >= 0) +        if (all_idx >= 0) {            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].blinkwait = 700L;              shape_table[idx].blinkon = 400L; @@ -208,6 +242,23 @@ char_u *parse_shape_opt(int what)        shape_table[SHAPE_IDX_VE].id_lm = shape_table[SHAPE_IDX_V].id_lm;      }    } - +  ui_cursor_style_set();    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; +} + diff --git a/src/nvim/cursor_shape.h b/src/nvim/cursor_shape.h index 9ce1b6e0a0..0006ede31d 100644 --- a/src/nvim/cursor_shape.h +++ b/src/nvim/cursor_shape.h @@ -1,32 +1,34 @@  #ifndef NVIM_CURSOR_SHAPE_H  #define NVIM_CURSOR_SHAPE_H -/* - * struct to store values from 'guicursor' and 'mouseshape' - */ -/* Indexes in shape_table[] */ -#define SHAPE_IDX_N     0       /* Normal mode */ -#define SHAPE_IDX_V     1       /* Visual mode */ -#define SHAPE_IDX_I     2       /* Insert mode */ -#define SHAPE_IDX_R     3       /* Replace mode */ -#define SHAPE_IDX_C     4       /* Command line Normal mode */ -#define SHAPE_IDX_CI    5       /* Command line Insert mode */ -#define SHAPE_IDX_CR    6       /* Command line Replace mode */ -#define SHAPE_IDX_O     7       /* Operator-pending mode */ -#define SHAPE_IDX_VE    8       /* Visual mode with 'selection' exclusive */ -#define SHAPE_IDX_CLINE 9       /* On command line */ -#define SHAPE_IDX_STATUS 10     /* A status line */ -#define SHAPE_IDX_SDRAG 11      /* dragging a status line */ -#define SHAPE_IDX_VSEP  12      /* A vertical separator line */ -#define SHAPE_IDX_VDRAG 13      /* dragging a vertical separator line */ -#define SHAPE_IDX_MORE  14      /* Hit-return or More */ -#define SHAPE_IDX_MOREL 15      /* Hit-return or More in last line */ -#define SHAPE_IDX_SM    16      /* showing matching paren */ -#define SHAPE_IDX_COUNT 17 +/// struct to store values from 'guicursor' and 'mouseshape' +/// Indexes in shape_table[] +typedef enum { +SHAPE_IDX_N      = 0,       ///< Normal mode +SHAPE_IDX_V      = 1,       ///< Visual mode +SHAPE_IDX_I      = 2,       ///< Insert mode +SHAPE_IDX_R      = 3,       ///< Replace mode +SHAPE_IDX_C      = 4,       ///< Command line Normal mode +SHAPE_IDX_CI     = 5,       ///< Command line Insert mode +SHAPE_IDX_CR     = 6,       ///< Command line Replace mode +SHAPE_IDX_O      = 7,       ///< Operator-pending mode +SHAPE_IDX_VE     = 8,       ///< Visual mode with 'selection' exclusive +SHAPE_IDX_CLINE  = 9,       ///< On command line +SHAPE_IDX_STATUS = 10,      ///< On status line +SHAPE_IDX_SDRAG  = 11,      ///< dragging a status line +SHAPE_IDX_VSEP   = 12,      ///< On vertical separator line +SHAPE_IDX_VDRAG  = 13,      ///< dragging a vertical separator line +SHAPE_IDX_MORE   = 14,      ///< Hit-return or More +SHAPE_IDX_MOREL  = 15,      ///< Hit-return or More in last line +SHAPE_IDX_SM     = 16,      ///< showing matching paren +SHAPE_IDX_COUNT  = 17 +} MouseMode; -#define SHAPE_BLOCK     0       /* block cursor */ -#define SHAPE_HOR       1       /* horizontal bar cursor */ -#define SHAPE_VER       2       /* vertical bar cursor */ +typedef enum { +SHAPE_BLOCK     = 0,       ///< block 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_HIDE     1       /* hide mouse pointer */ @@ -35,16 +37,17 @@  #define SHAPE_CURSOR    2       /* used for text cursor shape */  typedef struct cursor_entry { -  int shape;                    /* one of the SHAPE_ defines */ -  int mshape;                   /* one of the MSHAPE defines */ -  int percentage;               /* percentage of cell for bar */ -  long blinkwait;               /* blinking, wait time before blinking starts */ -  long blinkon;                 /* blinking, on time */ -  long blinkoff;                /* blinking, off time */ -  int id;                       /* highlight group ID */ -  int id_lm;                    /* highlight group ID for :lmap mode */ -  char        *name;            /* mode name (fixed) */ -  char used_for;                /* SHAPE_MOUSE and/or SHAPE_CURSOR */ +  char *full_name;        ///< mode description +  CursorShape shape;      ///< cursor shape: one of the SHAPE_ defines +  int mshape;             ///< mouse shape: one of the MSHAPE defines +  int percentage;         ///< percentage of cell for bar +  long blinkwait;         ///< blinking, wait time before blinking starts +  long blinkon;           ///< blinking, on time +  long blinkoff;          ///< blinking, off time +  int id;                 ///< highlight group ID +  int id_lm;              ///< highlight group ID for :lmap mode +  char *name;             ///< mode short name +  char used_for;          ///< SHAPE_MOUSE and/or SHAPE_CURSOR  } cursorentry_T; diff --git a/src/nvim/options.lua b/src/nvim/options.lua index 9dff3410d6..09f016cf5a 100644 --- a/src/nvim/options.lua +++ b/src/nvim/options.lua @@ -1000,7 +1000,7 @@ return {        deny_duplicates=true,        vi_def=true,        varname='p_guicursor', -      defaults={if_true={vi="n-v-c:block,o:hor50,i-ci:hor15,r-cr:hor30,sm:block"}} +      defaults={if_true={vi="n-v-c:block-Cursor/lCursor,ve:ver35-Cursor,o:hor50-Cursor,i-ci:ver25-Cursor/lCursor,r-cr:hor20-Cursor/lCursor,sm:block-Cursor-blinkwait175-blinkoff150-blinkon175"}}      },      {        full_name='guifont', abbreviation='gfn', diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c index 4a7b4a0eac..acda25e738 100644 --- a/src/nvim/syntax.c +++ b/src/nvim/syntax.c @@ -42,34 +42,38 @@  static bool did_syntax_onoff = false; -// 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 highlight_ga array PLUS ONE. +/// 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 highlight_ga array PLUS ONE.  struct hl_group { -  char_u      *sg_name;         // highlight group name -  char_u      *sg_name_u;       // uppercase of sg_name -  int sg_attr;                  // Screen attr -  int sg_link;                  // link to this highlight group ID -  int sg_set;                   // combination of SG_* flags -  scid_T sg_scriptID;           // script in which the group was last set +  char_u      *sg_name;         ///< highlight group name +  char_u      *sg_name_u;       ///< uppercase of sg_name +  int sg_attr;                  ///< Screen attr @see ATTR_ENTRY +  int sg_link;                  ///< link to this highlight group ID +  int sg_set;                   ///< combination of flags in \ref SG_SET +  scid_T sg_scriptID;           ///< script in which the group was last set    // for terminal UIs -  int sg_cterm;                 // "cterm=" highlighting attr -  int sg_cterm_fg;              // terminal fg 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;                 ///< "cterm=" highlighting attr +  int sg_cterm_fg;              ///< terminal fg color number + 1 +  int sg_cterm_bg;              ///< terminal bg color number + 1 +  int sg_cterm_bold;            ///< bold attr was set for light color    // for RGB UIs -  int sg_gui;                   // "gui=" highlighting attributes -  RgbValue sg_rgb_fg;           // RGB foreground color -  RgbValue sg_rgb_bg;           // RGB background color -  RgbValue sg_rgb_sp;           // RGB special color -  uint8_t *sg_rgb_fg_name;      // RGB foreground color name -  uint8_t *sg_rgb_bg_name;      // RGB background color name -  uint8_t *sg_rgb_sp_name;      // RGB special color name +  int sg_gui;                   ///< "gui=" highlighting attributes +                                ///< (combination of \ref HL_ATTRIBUTES) +  RgbValue sg_rgb_fg;           ///< RGB foreground color +  RgbValue sg_rgb_bg;           ///< RGB background color +  RgbValue sg_rgb_sp;           ///< RGB special color +  uint8_t *sg_rgb_fg_name;      ///< RGB foreground color name +  uint8_t *sg_rgb_bg_name;      ///< RGB background color name +  uint8_t *sg_rgb_sp_name;      ///< RGB special color name  }; +/// \addtogroup SG_SET +/// @{  #define SG_CTERM        2       // cterm has been set  #define SG_GUI          4       // gui has been set  #define SG_LINK         8       // link has been set +/// @}  // highlight groups for 'highlight' option  static garray_T highlight_ga = GA_EMPTY_INIT_VALUE; @@ -6093,16 +6097,16 @@ int load_colors(char_u *name)    return retval;  } -/* - * Handle the ":highlight .." command. - * When using ":hi clear" this is called recursively for each group with - * "forceit" and "init" both TRUE. - */ -void  -do_highlight ( + +/// Handle the ":highlight .." command. +/// When using ":hi clear" this is called recursively for each group with +/// "forceit" and "init" both TRUE. +/// @param init TRUE when called for initializing +void +do_highlight(      char_u *line,      int forceit, -    int init                   /* TRUE when called for initializing */ +    int init  )  {    char_u      *name_end; @@ -6704,12 +6708,10 @@ static garray_T attr_table = GA_EMPTY_INIT_VALUE;  #define ATTR_ENTRY(idx) ((attrentry_T *)attr_table.ga_data)[idx] -/* - * Return the attr number for a set of colors and font. - * Add a new entry to the term_attr_table, attr_table or gui_attr_table - * if the combination is new. - * Return 0 for error. - */ +/// Return the attr number for a set of colors and font. +/// Add a new entry to the term_attr_table, attr_table or gui_attr_table +/// if the combination is new. +/// @return 0 for error.  int get_attr_entry(attrentry_T *aep)  {    garray_T *table = &attr_table; @@ -6932,7 +6934,7 @@ static int highlight_list_arg(int id, int didh, int type, int iarg, char_u *sarg  /// Check whether highlight group has attribute  /// -/// @param[in]  id  Highilght group to check. +/// @param[in]  id  Highlight group to check.  /// @param[in]  flag  Attribute to check.  /// @param[in]  modec  'g' for GUI, 'c' for term.  /// @@ -7165,12 +7167,13 @@ int syn_namen2id(char_u *linep, int len)    return id;  } -/* - * Find highlight group name in the table and return it's ID. - * 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. - * Return 0 for failure. - */ +/// Find highlight group name in the table and return it's ID. +/// If it doesn't exist yet, a new entry is created. +/// +/// @param pp Highlight group name +/// @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)  {    char_u  *name = vim_strnsave(pp, len); @@ -8244,7 +8247,14 @@ color_name_table_T color_name_table[] = {    { NULL, 0 },  }; -RgbValue name_to_color(uint8_t *name) + +/// Translate to RgbValue if \p name is an hex value (e.g. #XXXXXX), +/// else look into color_name_table to translate a color name to  its +/// hex value +/// +/// @param[in] name string value to convert to RGB +/// return the hex value or -1 if could not find a correct value +RgbValue name_to_color(const uint8_t *name)  {    if (name[0] == '#' && isxdigit(name[1]) && isxdigit(name[2]) diff --git a/src/nvim/syntax.h b/src/nvim/syntax.h index af2ac719c6..574e3372e2 100644 --- a/src/nvim/syntax.h +++ b/src/nvim/syntax.h @@ -5,10 +5,11 @@  #include "nvim/buffer_defs.h" -/* - * Terminal highlighting attribute bits. - * Attributes above HL_ALL are used for syntax highlighting. - */ + +/// Terminal highlighting attribute bits. +/// Attributes above HL_ALL are used for syntax highlighting. +/// \addtogroup HL_ATTRIBUTES +/// @{  #define HL_NORMAL      0x00  #define HL_INVERSE     0x01  #define HL_BOLD        0x02 @@ -16,6 +17,7 @@  #define HL_UNDERLINE   0x08  #define HL_UNDERCURL   0x10  #define HL_STANDOUT    0x20 +/// @}  #define HL_CONTAINED   0x01    /* not used on toplevel */  #define HL_TRANSP      0x02    /* has no highlighting	*/ diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index ebdfb1e7a1..badc0cd870 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -31,6 +31,8 @@  #include "nvim/ugrid.h"  #include "nvim/tui/input.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  // flushing. No existing terminal will require 32 bytes to do that. @@ -69,13 +71,14 @@ typedef struct {    bool can_use_terminal_scroll;    bool mouse_enabled;    bool busy; +  cursorentry_T cursor_shapes[SHAPE_IDX_COUNT];    HlAttrs print_attrs;    int showing_mode;    struct {      int enable_mouse, disable_mouse;      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_cursor_color;      int enable_focus_reporting, disable_focus_reporting;    } unibi_ext;  } TUIData; @@ -97,6 +100,7 @@ UI *tui_start(void)    ui->clear = tui_clear;    ui->eol_clear = tui_eol_clear;    ui->cursor_goto = tui_cursor_goto; +  ui->cursor_style_set = tui_cursor_style_set;    ui->update_menu = tui_update_menu;    ui->busy_start = tui_busy_start;    ui->busy_stop = tui_busy_stop; @@ -129,11 +133,9 @@ static void terminfo_start(UI *ui)    data->showing_mode = 0;    data->unibi_ext.enable_mouse = -1;    data->unibi_ext.disable_mouse = -1; +  data->unibi_ext.set_cursor_color = -1;    data->unibi_ext.enable_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.disable_focus_reporting = -1;    data->out_fd = 1; @@ -146,8 +148,6 @@ static void terminfo_start(UI *ui)      data->ut = unibi_dummy();    }    fix_terminfo(data); -  // Initialize the cursor shape. -  unibi_out(ui, data->unibi_ext.set_cursor_shape_block);    // Set 't_Co' from the result of unibilium & fix_terminfo.    t_colors = unibi_get_num(data->ut, unibi_max_colors);    // Enter alternate screen and clear @@ -434,6 +434,64 @@ static void tui_cursor_goto(UI *ui, int row, int 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 redraw +  MouseMode cursor_mode = tui_mode2cursor(data->showing_mode); +  tui_set_cursor(ui, cursor_mode); +} +  static void tui_update_menu(UI *ui)  {      // Do nothing; menus are for GUI only @@ -467,33 +525,101 @@ 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; +    } +    data->params[0].i = shape; +    data->params[1].i = (c.blinkon == 0); + +    unibi_format(vars, vars + 26, +      TMUX_WRAP("\x1b]50;CursorShape=%p1%d;BlinkingCursorEnabled=%p2%d\x07"), +      data->params, out, ui, NULL, NULL); +  } 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); +  } + +  if (c.id != 0 && ui->rgb) { +    int attr = syn_id2attr(c.id); +    attrentry_T *aep = syn_cterm_attr2entry(attr); +    data->params[0].i = aep->rgb_bg_color; +    unibi_out(ui, data->unibi_ext.set_cursor_color); +  } +} + +/// 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)  {    TUIData *data = ui->data;    if (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) {      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) {      if (data->showing_mode != REPLACE) { -      unibi_out(ui, data->unibi_ext.set_cursor_shape_ul); +      tui_set_cursor(ui, SHAPE_IDX_R);      }    } else {      assert(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;  }  static void tui_set_scroll_region(UI *ui, int top, int bot, int left, -    int right) +                                  int right)  {    TUIData *data = ui->data;    ugrid_set_scroll_region(&data->grid, top, bot, left, right); @@ -831,8 +957,6 @@ static void fix_terminfo(TUIData *data)      goto end;    } -  bool inside_tmux = os_getenv("TMUX") != NULL; -  #define STARTS_WITH(str, prefix) (!memcmp(str, prefix, sizeof(prefix) - 1))    if (STARTS_WITH(term, "rxvt")) { @@ -890,42 +1014,10 @@ static void fix_terminfo(TUIData *data)      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:    // Fill some empty slots with common terminal strings +  data->unibi_ext.set_cursor_color = (int)unibi_add_ext_str( +      ut, NULL, "\033]12;#%p1%06x\007");    data->unibi_ext.enable_mouse = (int)unibi_add_ext_str(ut, NULL,        "\x1b[?1002h\x1b[?1006h");    data->unibi_ext.disable_mouse = (int)unibi_add_ext_str(ut, NULL, diff --git a/src/nvim/tui/tui.h b/src/nvim/tui/tui.h index 07523bc124..2915b0e2f8 100644 --- a/src/nvim/tui/tui.h +++ b/src/nvim/tui/tui.h @@ -1,6 +1,8 @@  #ifndef NVIM_TUI_TUI_H  #define NVIM_TUI_TUI_H +#include "nvim/cursor_shape.h" +  #ifdef INCLUDE_GENERATED_DECLARATIONS  # include "tui/tui.h.generated.h"  #endif diff --git a/src/nvim/ui.c b/src/nvim/ui.c index ea42e3e357..babb4efa96 100644 --- a/src/nvim/ui.c +++ b/src/nvim/ui.c @@ -29,6 +29,7 @@  #include "nvim/screen.h"  #include "nvim/syntax.h"  #include "nvim/window.h" +#include "nvim/cursor_shape.h"  #ifdef FEAT_TUI  # include "nvim/tui/tui.h"  #else @@ -179,6 +180,7 @@ void ui_refresh(void)    row = col = 0;    screen_resize(width, height);    pum_set_external(pum_external); +  ui_cursor_style_set();  }  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;  } +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)  {      UI_CALL(update_menu); diff --git a/src/nvim/ui.h b/src/nvim/ui.h index d14bc5812c..0af0c0db65 100644 --- a/src/nvim/ui.h +++ b/src/nvim/ui.h @@ -22,6 +22,7 @@ struct ui_t {    void (*clear)(UI *ui);    void (*eol_clear)(UI *ui);    void (*cursor_goto)(UI *ui, int row, int col); +  void (*cursor_style_set)(UI *ui, Dictionary cursor_shapes);    void (*update_menu)(UI *ui);    void (*busy_start)(UI *ui);    void (*busy_stop)(UI *ui); diff --git a/src/nvim/ui_bridge.c b/src/nvim/ui_bridge.c index 25861abc1b..c9bad6b254 100644 --- a/src/nvim/ui_bridge.c +++ b/src/nvim/ui_bridge.c @@ -13,6 +13,7 @@  #include "nvim/memory.h"  #include "nvim/ui_bridge.h"  #include "nvim/ugrid.h" +#include "nvim/api/private/helpers.h"  #ifdef INCLUDE_GENERATED_DECLARATIONS  # 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.eol_clear = ui_bridge_eol_clear;    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.busy_start = ui_bridge_busy_start;    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]));  } +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)  {    UI_CALL(b, update_menu, 1, b); | 
