diff options
Diffstat (limited to 'src/nvim/ui.c')
| -rw-r--r-- | src/nvim/ui.c | 435 | 
1 files changed, 209 insertions, 226 deletions
| diff --git a/src/nvim/ui.c b/src/nvim/ui.c index 28f71b7ef2..42366fdb76 100644 --- a/src/nvim/ui.c +++ b/src/nvim/ui.c @@ -1,3 +1,6 @@ +// This is an open source non-commercial project. Dear PVS-Studio, please check +// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +  #include <assert.h>  #include <inttypes.h>  #include <stdbool.h> @@ -5,11 +8,13 @@  #include <limits.h>  #include "nvim/vim.h" +#include "nvim/log.h"  #include "nvim/ui.h"  #include "nvim/charset.h"  #include "nvim/cursor.h"  #include "nvim/diff.h"  #include "nvim/ex_cmds2.h" +#include "nvim/ex_getln.h"  #include "nvim/fold.h"  #include "nvim/main.h"  #include "nvim/ascii.h" @@ -44,15 +49,38 @@  #define MAX_UI_COUNT 16  static UI *uis[MAX_UI_COUNT]; +static bool ui_ext[kUIExtCount] = { 0 };  static size_t ui_count = 0;  static int row = 0, col = 0;  static struct {    int top, bot, left, right;  } sr; -static int current_attr_code = 0; +static int current_attr_code = -1;  static bool pending_cursor_update = false;  static int busy = 0;  static int height, width; +static int old_mode_idx = -1; + +#if MIN_LOG_LEVEL > DEBUG_LOG_LEVEL +# define UI_LOG(funname, ...) +#else +static size_t uilog_seen = 0; +static char uilog_last_event[1024] = { 0 }; +# define UI_LOG(funname, ...) \ +  do { \ +    if (strequal(uilog_last_event, STR(funname))) { \ +      uilog_seen++; \ +    } else { \ +      if (uilog_seen > 0) { \ +        do_log(DEBUG_LOG_LEVEL, "UI: ", NULL, -1, true, \ +               "%s (+%zu times...)", uilog_last_event, uilog_seen); \ +      } \ +      do_log(DEBUG_LOG_LEVEL, "UI: ", NULL, -1, true, STR(funname)); \ +      uilog_seen = 0; \ +      xstrlcpy(uilog_last_event, STR(funname), sizeof(uilog_last_event)); \ +    } \ +  } while (0) +#endif  // UI_CALL invokes a function on all registered UI instances. The functions can  // have 0-5 arguments (configurable by SELECT_NTH). @@ -62,6 +90,7 @@ static int height, width;  # define UI_CALL(funname, ...) \      do { \        flush_cursor_update(); \ +      UI_LOG(funname, 0); \        for (size_t i = 0; i < ui_count; i++) { \          UI *ui = uis[i]; \          UI_CALL_MORE(funname, __VA_ARGS__); \ @@ -71,19 +100,26 @@ static int height, width;  # define UI_CALL(...) \      do { \        flush_cursor_update(); \ +      UI_LOG(__VA_ARGS__, 0); \        for (size_t i = 0; i < ui_count; i++) { \          UI *ui = uis[i]; \          UI_CALL_HELPER(CNT(__VA_ARGS__), __VA_ARGS__); \        } \      } while (0)  #endif -#define CNT(...) SELECT_NTH(__VA_ARGS__, MORE, MORE, MORE, MORE, ZERO, ignore) -#define SELECT_NTH(a1, a2, a3, a4, a5, a6, ...) a6 +#define CNT(...) SELECT_NTH(__VA_ARGS__, MORE, MORE, MORE, \ +                            MORE, MORE, ZERO, ignore) +#define SELECT_NTH(a1, a2, a3, a4, a5, a6, a7, ...) a7  #define UI_CALL_HELPER(c, ...) UI_CALL_HELPER2(c, __VA_ARGS__) +// Resolves to UI_CALL_MORE or UI_CALL_ZERO.  #define UI_CALL_HELPER2(c, ...) UI_CALL_##c(__VA_ARGS__)  #define UI_CALL_MORE(method, ...) if (ui->method) ui->method(ui, __VA_ARGS__)  #define UI_CALL_ZERO(method) if (ui->method) ui->method(ui) +#ifdef INCLUDE_GENERATED_DECLARATIONS +# include "ui_events_call.generated.h" +#endif +  void ui_builtin_start(void)  {  #ifdef FEAT_TUI @@ -110,6 +146,9 @@ void ui_builtin_stop(void)  bool ui_rgb_attached(void)  { +  if (!headless_mode && p_tgc) { +    return true; +  }    for (size_t i = 0; i < ui_count; i++) {      if (uis[i]->rgb) {        return true; @@ -123,24 +162,6 @@ bool ui_active(void)    return ui_count != 0;  } -void ui_suspend(void) -{ -  UI_CALL(suspend); -  UI_CALL(flush); -} - -void ui_set_title(char *title) -{ -  UI_CALL(set_title, title); -  UI_CALL(flush); -} - -void ui_set_icon(char *icon) -{ -  UI_CALL(set_icon, icon); -  UI_CALL(flush); -} -  void ui_event(char *name, Array args)  {    bool args_consumed = false; @@ -150,10 +171,65 @@ void ui_event(char *name, Array args)    }  } -// May update the shape of the cursor. -void ui_cursor_shape(void) + +/// Converts an HlAttrs into Dictionary +/// +/// @param[in] aep data to convert +/// @param use_rgb use 'gui*' settings if true, else resorts to 'cterm*' +Dictionary hlattrs2dict(const HlAttrs *aep, bool use_rgb)  { -  ui_mode_change(); +  assert(aep); +  Dictionary hl = ARRAY_DICT_INIT; +  int mask  = use_rgb ? aep->rgb_ae_attr : aep->cterm_ae_attr; + +  if (mask & HL_BOLD) { +    PUT(hl, "bold", BOOLEAN_OBJ(true)); +  } + +  if (mask & HL_STANDOUT) { +    PUT(hl, "standout", BOOLEAN_OBJ(true)); +  } + +  if (mask & HL_UNDERLINE) { +    PUT(hl, "underline", BOOLEAN_OBJ(true)); +  } + +  if (mask & HL_UNDERCURL) { +    PUT(hl, "undercurl", BOOLEAN_OBJ(true)); +  } + +  if (mask & HL_ITALIC) { +    PUT(hl, "italic", BOOLEAN_OBJ(true)); +  } + +  if (mask & HL_INVERSE) { +    PUT(hl, "reverse", BOOLEAN_OBJ(true)); +  } + + +  if (use_rgb) { +    if (aep->rgb_fg_color != -1) { +      PUT(hl, "foreground", INTEGER_OBJ(aep->rgb_fg_color)); +    } + +    if (aep->rgb_bg_color != -1) { +      PUT(hl, "background", INTEGER_OBJ(aep->rgb_bg_color)); +    } + +    if (aep->rgb_sp_color != -1) { +      PUT(hl, "special", INTEGER_OBJ(aep->rgb_sp_color)); +    } +  } else { +    if (cterm_normal_fg_color != aep->cterm_fg_color) { +      PUT(hl, "foreground", INTEGER_OBJ(aep->cterm_fg_color - 1)); +    } + +    if (cterm_normal_bg_color != aep->cterm_bg_color) { +      PUT(hl, "background", INTEGER_OBJ(aep->cterm_bg_color - 1)); +    } +  } + +  return hl;  }  void ui_refresh(void) @@ -168,19 +244,36 @@ void ui_refresh(void)    }    int width = INT_MAX, height = INT_MAX; -  bool pum_external = true; +  bool ext_widgets[kUIExtCount]; +  for (UIExtension i = 0; (int)i < kUIExtCount; i++) { +    ext_widgets[i] = true; +  }    for (size_t i = 0; i < ui_count; i++) {      UI *ui = uis[i];      width = MIN(ui->width, width);      height = MIN(ui->height, height); -    pum_external &= ui->pum_external; +    for (UIExtension i = 0; (int)i < kUIExtCount; i++) { +      ext_widgets[i] &= ui->ui_ext[i]; +    }    }    row = col = 0; + +  int save_p_lz = p_lz; +  p_lz = false;  // convince redrawing() to return true ...    screen_resize(width, height); -  pum_set_external(pum_external); -  ui_cursor_style_set(); +  p_lz = save_p_lz; + +  for (UIExtension i = 0; (int)i < kUIExtCount; i++) { +    ui_ext[i] = ext_widgets[i]; +    ui_call_option_set(cstr_as_string((char *)ui_ext_names[i]), +                       BOOLEAN_OBJ(ext_widgets[i])); +  } +  ui_mode_info_set(); +  old_mode_idx = -1; +  ui_cursor_shape(); +  current_attr_code = -1;  }  static void ui_refresh_event(void **argv) @@ -190,7 +283,7 @@ static void ui_refresh_event(void **argv)  void ui_schedule_refresh(void)  { -  loop_schedule(&main_loop, event_create(1, ui_refresh_event, 0)); +  loop_schedule(&main_loop, event_create(ui_refresh_event, 0));  }  void ui_resize(int new_width, int new_height) @@ -198,6 +291,11 @@ void ui_resize(int new_width, int new_height)    width = new_width;    height = new_height; +  // TODO(bfredl): update default colors when they changed, NOT on resize. +  ui_call_default_colors_set(normal_fg, normal_bg, normal_sp, +                             cterm_normal_fg_color, cterm_normal_bg_color); + +  // Deprecated:    UI_CALL(update_fg, (ui->rgb ? normal_fg : cterm_normal_fg_color - 1));    UI_CALL(update_bg, (ui->rgb ? normal_bg : cterm_normal_bg_color - 1));    UI_CALL(update_sp, (ui->rgb ? normal_sp : -1)); @@ -206,33 +304,23 @@ void ui_resize(int new_width, int new_height)    sr.bot = height - 1;    sr.left = 0;    sr.right = width - 1; -  UI_CALL(resize, width, height); +  ui_call_resize(width, height);  }  void ui_busy_start(void)  {    if (!(busy++)) { -    UI_CALL(busy_start); +    ui_call_busy_start();    }  }  void ui_busy_stop(void)  {    if (!(--busy)) { -    UI_CALL(busy_stop); +    ui_call_busy_stop();    }  } -void ui_mouse_on(void) -{ -  UI_CALL(mouse_on); -} - -void ui_mouse_off(void) -{ -  UI_CALL(mouse_off); -} -  void ui_attach_impl(UI *ui)  {    if (ui_count == MAX_UI_COUNT) { @@ -240,6 +328,7 @@ void ui_attach_impl(UI *ui)    }    uis[ui_count++] = ui; +  ui_refresh_options();    ui_refresh();  } @@ -273,11 +362,6 @@ void ui_detach_impl(UI *ui)    }  } -void ui_clear(void) -{ -  UI_CALL(clear); -} -  // Set scrolling region for window 'wp'.  // The region starts 'off' lines from the start of the window.  // Also set the vertical scroll region for a vertically split window.  Always @@ -292,7 +376,7 @@ void ui_set_scroll_region(win_T *wp, int off)      sr.right = wp->w_wincol + wp->w_width - 1;    } -  UI_CALL(set_scroll_region, sr.top, sr.bot, sr.left, sr.right); +  ui_call_set_scroll_region(sr.top, sr.bot, sr.left, sr.right);  }  // Reset scrolling region to the whole screen. @@ -302,62 +386,63 @@ void ui_reset_scroll_region(void)    sr.bot = (int)Rows - 1;    sr.left = 0;    sr.right = (int)Columns - 1; -  UI_CALL(set_scroll_region, sr.top, sr.bot, sr.left, sr.right); +  ui_call_set_scroll_region(sr.top, sr.bot, sr.left, sr.right);  } -void ui_append_lines(int count) +void ui_set_highlight(int attr_code)  { -  UI_CALL(scroll, -count); -} - -void ui_delete_lines(int count) -{ -  UI_CALL(scroll, count); -} - -void ui_eol_clear(void) -{ -  UI_CALL(eol_clear); -} - -void ui_start_highlight(int attr_code) -{ -  current_attr_code = attr_code; - -  if (!ui_count) { +  if (current_attr_code == attr_code) {      return;    } +  current_attr_code = attr_code; -  set_highlight_args(current_attr_code); -} - -void ui_stop_highlight(void) -{ -  current_attr_code = HL_NORMAL; +  HlAttrs attrs = HLATTRS_INIT; -  if (!ui_count) { -    return; +  if (attr_code != 0) { +    HlAttrs *aep = syn_cterm_attr2entry(attr_code); +    if (aep) { +      attrs = *aep; +    }    } -  set_highlight_args(current_attr_code); +  UI_CALL(highlight_set, attrs);  } -void ui_visual_bell(void) +void ui_clear_highlight(void)  { -  UI_CALL(visual_bell); +  ui_set_highlight(0);  }  void ui_puts(uint8_t *str)  { -  uint8_t *ptr = str; +  uint8_t *p = str;    uint8_t c; -  while ((c = *ptr)) { +  while ((c = *p)) {      if (c < 0x20) { -      parse_control_character(c); -      ptr++; -    } else { -      send_output(&ptr); +      abort(); +    } + +    size_t clen = (size_t)mb_ptr2len(p); +    ui_call_put((String){ .data = (char *)p, .size = clen }); +    col++; +    if (mb_ptr2cells(p) > 1) { +      // double cell character, blank the next cell +      ui_call_put((String)STRING_INIT); +      col++; +    } +    if (utf_ambiguous_width(utf_ptr2char(p))) { +      pending_cursor_update = true; +    } +    if (col >= width) { +      ui_linefeed(); +    } +    p += clen; + +    if (p_wd) {  // 'writedelay': flush & delay each time. +      ui_flush(); +      uint64_t wd = (uint64_t)labs(p_wd); +      os_delay(wd, false);      }    }  } @@ -378,17 +463,12 @@ void ui_cursor_goto(int new_row, int new_col)    pending_cursor_update = true;  } -void ui_cursor_style_set(void) +void ui_mode_info_set(void)  { -  Dictionary style = cursor_shape_dict(); +  Array style = mode_style_array();    bool enabled = (*p_guicursor != NUL); -  UI_CALL(cursor_style_set, enabled, style); -  api_free_dictionary(style); -} - -void ui_update_menu(void) -{ -    UI_CALL(update_menu); +  ui_call_mode_info_set(enabled, style); +  api_free_array(style);  }  int ui_current_row(void) @@ -403,163 +483,66 @@ int ui_current_col(void)  void ui_flush(void)  { -  UI_CALL(flush); -} - -static void send_output(uint8_t **ptr) -{ -  uint8_t *p = *ptr; - -  while (*p >= 0x20) { -    size_t clen = (size_t)mb_ptr2len(p); -    UI_CALL(put, p, (size_t)clen); -    col++; -    if (mb_ptr2cells(p) > 1) { -      // double cell character, blank the next cell -      UI_CALL(put, NULL, 0); -      col++; -    } -    if (utf_ambiguous_width(utf_ptr2char(p))) { -      pending_cursor_update = true; -    } -    if (col >= width) { -      ui_linefeed(); -    } -    p += clen; -  } - -  *ptr = p; -} - -static void parse_control_character(uint8_t c) -{ -  if (c == '\n') { -    ui_linefeed(); -  } else if (c == '\r') { -    ui_carriage_return(); -  } else if (c == '\b') { -    ui_cursor_left(); -  } else if (c == Ctrl_L) { -    ui_cursor_right(); -  } else if (c == Ctrl_G) { -    UI_CALL(bell); -  } +  cmdline_ui_flush(); +  ui_call_flush();  } -static void set_highlight_args(int attr_code) -{ -  HlAttrs rgb_attrs = { false, false, false, false, false, -1, -1, -1 }; -  HlAttrs cterm_attrs = rgb_attrs; - -  if (attr_code == HL_NORMAL) { -    goto end; -  } - -  int rgb_mask = 0; -  int cterm_mask = 0; -  attrentry_T *aep = syn_cterm_attr2entry(attr_code); - -  if (!aep) { -    goto end; -  } - -  rgb_mask = aep->rgb_ae_attr; -  cterm_mask = aep->cterm_ae_attr; - -  rgb_attrs.bold = rgb_mask & HL_BOLD; -  rgb_attrs.underline = rgb_mask & HL_UNDERLINE; -  rgb_attrs.undercurl = rgb_mask & HL_UNDERCURL; -  rgb_attrs.italic = rgb_mask & HL_ITALIC; -  rgb_attrs.reverse = rgb_mask & (HL_INVERSE | HL_STANDOUT); -  cterm_attrs.bold = cterm_mask & HL_BOLD; -  cterm_attrs.underline = cterm_mask & HL_UNDERLINE; -  cterm_attrs.undercurl = cterm_mask & HL_UNDERCURL; -  cterm_attrs.italic = cterm_mask & HL_ITALIC; -  cterm_attrs.reverse = cterm_mask & (HL_INVERSE | HL_STANDOUT); - -  if (aep->rgb_fg_color != normal_fg) { -    rgb_attrs.foreground = aep->rgb_fg_color; -  } - -  if (aep->rgb_bg_color != normal_bg) { -    rgb_attrs.background = aep->rgb_bg_color; -  } - -  if (aep->rgb_sp_color != normal_sp) { -    rgb_attrs.special = aep->rgb_sp_color; -  } - -  if (cterm_normal_fg_color != aep->cterm_fg_color) { -    cterm_attrs.foreground = aep->cterm_fg_color - 1; -  } -  if (cterm_normal_bg_color != aep->cterm_bg_color) { -    cterm_attrs.background = aep->cterm_bg_color - 1; -  } - -end: -  UI_CALL(highlight_set, (ui->rgb ? rgb_attrs : cterm_attrs)); -} - -static void ui_linefeed(void) +void ui_linefeed(void)  {    int new_col = 0;    int new_row = row;    if (new_row < sr.bot) {      new_row++;    } else { -    UI_CALL(scroll, 1); +    ui_call_scroll(1);    }    ui_cursor_goto(new_row, new_col);  } -static void ui_carriage_return(void) -{ -  int new_col = 0; -  ui_cursor_goto(row, new_col); -} - -static void ui_cursor_left(void) -{ -  int new_col = col - 1; -  assert(new_col >= 0); -  ui_cursor_goto(row, new_col); -} - -static void ui_cursor_right(void) -{ -  int new_col = col + 1; -  assert(new_col < width); -  ui_cursor_goto(row, new_col); -} -  static void flush_cursor_update(void)  {    if (pending_cursor_update) {      pending_cursor_update = false; -    UI_CALL(cursor_goto, row, col); +    ui_call_cursor_goto(row, col);    }  } -// Notify that the current mode has changed. Can be used to change cursor -// shape, for example. -static void ui_mode_change(void) +/// Check if current mode has changed. +/// May update the shape of the cursor. +void ui_cursor_shape(void)  { -  int mode;    if (!full_screen) {      return;    } -  // Get a simple UI mode out of State. -  if ((State & REPLACE) == REPLACE) { -    mode = REPLACE; -  } else if (State & INSERT) { -    mode = INSERT; -  } else if (State & CMDLINE) { -    mode = CMDLINE; -  } else { -    mode = NORMAL; +  int mode_idx = cursor_get_mode_idx(); + +  if (old_mode_idx != mode_idx) { +    old_mode_idx = mode_idx; +    char *full_name = shape_table[mode_idx].full_name; +    ui_call_mode_change(cstr_as_string(full_name), mode_idx);    } -  UI_CALL(mode_change, mode);    conceal_check_cursur_line();  } +/// Returns true if `widget` is externalized. +bool ui_is_external(UIExtension widget) +{ +  return ui_ext[widget]; +} + +Array ui_array(void) +{ +  Array all_uis = ARRAY_DICT_INIT; +  for (size_t i = 0; i < ui_count; i++) { +    Dictionary dic = ARRAY_DICT_INIT; +    PUT(dic, "width", INTEGER_OBJ(uis[i]->width)); +    PUT(dic, "height", INTEGER_OBJ(uis[i]->height)); +    PUT(dic, "rgb", BOOLEAN_OBJ(uis[i]->rgb)); +    for (UIExtension j = 0; j < kUIExtCount; j++) { +      PUT(dic, ui_ext_names[j], BOOLEAN_OBJ(uis[i]->ui_ext[j])); +    } +    ADD(all_uis, DICTIONARY_OBJ(dic)); +  } +  return all_uis; +} | 
