diff options
| author | ZyX <kp-pav@yandex.ru> | 2017-12-03 16:49:30 +0300 | 
|---|---|---|
| committer | ZyX <kp-pav@yandex.ru> | 2017-12-03 16:49:30 +0300 | 
| commit | c49e22d3964d6c7ae1c24e8ad01b5fec4ca40b57 (patch) | |
| tree | b7e59c416d1435725c65f8952b6e55c70544d97e /src/nvim/ui.c | |
| parent | 62108c3b0be46936c83f6d4c98b44ceb5e6f77fd (diff) | |
| parent | 27a577586eace687c47e7398845178208cae524a (diff) | |
| download | rneovim-c49e22d3964d6c7ae1c24e8ad01b5fec4ca40b57.tar.gz rneovim-c49e22d3964d6c7ae1c24e8ad01b5fec4ca40b57.tar.bz2 rneovim-c49e22d3964d6c7ae1c24e8ad01b5fec4ca40b57.zip  | |
Merge branch 'master' into s-dash-stdin
Diffstat (limited to 'src/nvim/ui.c')
| -rw-r--r-- | src/nvim/ui.c | 383 | 
1 files changed, 195 insertions, 188 deletions
diff --git a/src/nvim/ui.c b/src/nvim/ui.c index ea42e3e357..3b8b3ac9a7 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" @@ -29,6 +34,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 @@ -43,6 +49,7 @@  #define MAX_UI_COUNT 16  static UI *uis[MAX_UI_COUNT]; +static bool ui_ext[UI_WIDGETS] = { 0 };  static size_t ui_count = 0;  static int row = 0, col = 0;  static struct { @@ -52,6 +59,28 @@ static int current_attr_code = 0;  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). @@ -61,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__); \ @@ -70,6 +100,7 @@ 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__); \ @@ -79,10 +110,15 @@ static int height, width;  #define CNT(...) SELECT_NTH(__VA_ARGS__, MORE, MORE, MORE, MORE, ZERO, ignore)  #define SELECT_NTH(a1, a2, a3, a4, a5, a6, ...) a6  #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 @@ -122,24 +158,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; @@ -149,10 +167,88 @@ void ui_event(char *name, Array args)    }  } -// May update the shape of the cursor. -void ui_cursor_shape(void) + +/// Converts an attrentry_T into an HlAttrs +/// +/// @param[in] aep data to convert +/// @param use_rgb use 'gui*' settings if true, else resorts to 'cterm*' +HlAttrs attrentry2hlattrs(const attrentry_T *aep, bool use_rgb) +{ +  assert(aep); + +  HlAttrs attrs = HLATTRS_INIT; +  int mask = 0; + +  mask = use_rgb ? aep->rgb_ae_attr : aep->cterm_ae_attr; + +  attrs.bold = mask & HL_BOLD; +  attrs.underline = mask & HL_UNDERLINE; +  attrs.undercurl = mask & HL_UNDERCURL; +  attrs.italic = mask & HL_ITALIC; +  attrs.reverse = mask & (HL_INVERSE | HL_STANDOUT); + +  if (use_rgb) { +    if (aep->rgb_fg_color != -1) { +      attrs.foreground = aep->rgb_fg_color; +    } + +    if (aep->rgb_bg_color != -1) { +      attrs.background = aep->rgb_bg_color; +    } + +    if (aep->rgb_sp_color != -1) { +      attrs.special = aep->rgb_sp_color; +    } +  } else { +    if (cterm_normal_fg_color != aep->cterm_fg_color) { +      attrs.foreground = aep->cterm_fg_color - 1; +    } + +    if (cterm_normal_bg_color != aep->cterm_bg_color) { +        attrs.background = aep->cterm_bg_color - 1; +    } +  } + +  return attrs; +} + +Dictionary hlattrs2dict(HlAttrs attrs)  { -  ui_mode_change(); +  Dictionary hl = ARRAY_DICT_INIT; + +  if (attrs.bold) { +    PUT(hl, "bold", BOOLEAN_OBJ(true)); +  } + +  if (attrs.underline) { +    PUT(hl, "underline", BOOLEAN_OBJ(true)); +  } + +  if (attrs.undercurl) { +    PUT(hl, "undercurl", BOOLEAN_OBJ(true)); +  } + +  if (attrs.italic) { +    PUT(hl, "italic", BOOLEAN_OBJ(true)); +  } + +  if (attrs.reverse) { +    PUT(hl, "reverse", BOOLEAN_OBJ(true)); +  } + +  if (attrs.foreground != -1) { +    PUT(hl, "foreground", INTEGER_OBJ(attrs.foreground)); +  } + +  if (attrs.background != -1) { +    PUT(hl, "background", INTEGER_OBJ(attrs.background)); +  } + +  if (attrs.special != -1) { +    PUT(hl, "special", INTEGER_OBJ(attrs.special)); +  } + +  return hl;  }  void ui_refresh(void) @@ -167,18 +263,33 @@ void ui_refresh(void)    }    int width = INT_MAX, height = INT_MAX; -  bool pum_external = true; +  bool ext_widgets[UI_WIDGETS]; +  for (UIWidget i = 0; (int)i < UI_WIDGETS; 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 (UIWidget i = 0; (int)i < UI_WIDGETS; 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); +  p_lz = save_p_lz; + +  for (UIWidget i = 0; (int)i < UI_WIDGETS; i++) { +    ui_set_external(i, ext_widgets[i]); +  } +  ui_mode_info_set(); +  old_mode_idx = -1; +  ui_cursor_shape();  }  static void ui_refresh_event(void **argv) @@ -188,7 +299,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) @@ -204,33 +315,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) { @@ -271,11 +372,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 @@ -290,7 +386,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. @@ -300,22 +396,7 @@ 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); -} - -void ui_append_lines(int count) -{ -  UI_CALL(scroll, -count); -} - -void ui_delete_lines(int count) -{ -  UI_CALL(scroll, count); -} - -void ui_eol_clear(void) -{ -  UI_CALL(eol_clear); +  ui_call_set_scroll_region(sr.top, sr.bot, sr.left, sr.right);  }  void ui_start_highlight(int attr_code) @@ -340,23 +421,31 @@ void ui_stop_highlight(void)    set_highlight_args(current_attr_code);  } -void ui_visual_bell(void) -{ -  UI_CALL(visual_bell); -} -  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;    }  } @@ -376,9 +465,12 @@ void ui_cursor_goto(int new_row, int new_col)    pending_cursor_update = true;  } -void ui_update_menu(void) +void ui_mode_info_set(void)  { -    UI_CALL(update_menu); +  Array style = mode_style_array(); +  bool enabled = (*p_guicursor != NUL); +  ui_call_mode_info_set(enabled, style); +  api_free_array(style);  }  int ui_current_row(void) @@ -393,163 +485,78 @@ 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 rgb_attrs = HLATTRS_INIT;    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; -  } +  rgb_attrs = attrentry2hlattrs(aep, true); +  cterm_attrs = attrentry2hlattrs(aep, false);  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(UIWidget widget) +{ +  return ui_ext[widget]; +} + +/// Sets `widget` as "external". +/// Such widgets are not drawn by Nvim; external UIs are expected to handle +/// higher-level UI events and present the data. +void ui_set_external(UIWidget widget, bool external) +{ +  ui_ext[widget] = external; +}  | 
