diff options
Diffstat (limited to 'src/nvim/screen.c')
-rw-r--r-- | src/nvim/screen.c | 280 |
1 files changed, 154 insertions, 126 deletions
diff --git a/src/nvim/screen.c b/src/nvim/screen.c index 34eef83164..c0db076eff 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -108,7 +108,6 @@ #include "nvim/menu.h" #include "nvim/message.h" #include "nvim/misc1.h" -#include "nvim/misc2.h" #include "nvim/garray.h" #include "nvim/move.h" #include "nvim/normal.h" @@ -120,6 +119,7 @@ #include "nvim/regexp.h" #include "nvim/search.h" #include "nvim/spell.h" +#include "nvim/state.h" #include "nvim/strings.h" #include "nvim/syntax.h" #include "nvim/terminal.h" @@ -420,9 +420,10 @@ void update_screen(int type) } } end_search_hl(); - /* May need to redraw the popup menu. */ - if (pum_visible()) + // May need to redraw the popup menu. + if (pum_drawn()) { pum_redraw(); + } /* Reset b_mod_set flags. Going through all windows is probably faster * than going through all buffers (there could be many buffers). */ @@ -485,6 +486,11 @@ void update_single_line(win_T *wp, linenr_T lnum) int row; int j; + // Don't do anything if the screen structures are (not yet) valid. + if (!screen_valid(true)) { + return; + } + if (lnum >= wp->w_topline && lnum < wp->w_botline && foldedCount(wp, lnum, &win_foldinfo) == 0) { row = 0; @@ -575,15 +581,6 @@ void update_debug_sign(buf_T *buf, linenr_T lnum) } /* - * Return TRUE when window "wp" has a column to draw signs in. - */ -static int draw_signcolumn(win_T *wp) -{ - return (wp->w_buffer->b_signlist != NULL); -} - - -/* * Update a single window. * * This may cause the windows below it also to be redrawn (when clearing the @@ -1400,7 +1397,7 @@ static void win_update(win_T *wp) && wp->w_lines[idx].wl_valid && wp->w_lines[idx].wl_lnum == lnum && lnum > wp->w_topline - && !(dy_flags & DY_LASTLINE) + && !(dy_flags & (DY_LASTLINE | DY_TRUNCATE)) && srow + wp->w_lines[idx].wl_size > wp->w_height && diff_check_fill(wp, lnum) == 0 ) { @@ -1483,10 +1480,20 @@ static void win_update(win_T *wp) /* Window ends in filler lines. */ wp->w_botline = lnum; wp->w_filler_rows = wp->w_height - srow; - } else if (dy_flags & DY_LASTLINE) { /* 'display' has "lastline" */ - /* - * Last line isn't finished: Display "@@@" at the end. - */ + } else if (dy_flags & DY_TRUNCATE) { // 'display' has "truncate" + int scr_row = wp->w_winrow + wp->w_height - 1; + + // Last line isn't finished: Display "@@@" in the last screen line. + screen_puts_len((char_u *)"@@", 2, scr_row, wp->w_wincol, + hl_attr(HLF_AT)); + + screen_fill(scr_row, scr_row + 1, + (int)wp->w_wincol + 2, (int)W_ENDCOL(wp), + '@', ' ', hl_attr(HLF_AT)); + set_empty_rows(wp, srow); + wp->w_botline = lnum; + } else if (dy_flags & DY_LASTLINE) { // 'display' has "lastline" + // Last line isn't finished: Display "@@@" at the end. screen_fill(wp->w_winrow + wp->w_height - 1, wp->w_winrow + wp->w_height, W_ENDCOL(wp) - 3, W_ENDCOL(wp), @@ -1587,7 +1594,7 @@ static void win_draw_end(win_T *wp, int c1, int c2, int row, int endrow, hlf_T h ' ', ' ', hl_attr(HLF_FC)); } - if (draw_signcolumn(wp)) { + if (signcolumn_on(wp)) { int nn = n + 2; /* draw the sign column left of the fold column */ @@ -1628,8 +1635,7 @@ static void win_draw_end(win_T *wp, int c1, int c2, int row, int endrow, hlf_T h n = nn; } - if (draw_signcolumn(wp)) - { + if (signcolumn_on(wp)) { int nn = n + 2; /* draw the sign column after the fold column */ @@ -1741,8 +1747,8 @@ static void fold_line(win_T *wp, long fold_count, foldinfo_T *foldinfo, linenr_T * text */ RL_MEMSET(col, hl_attr(HLF_FL), wp->w_width - col); - /* If signs are being displayed, add two spaces. */ - if (draw_signcolumn(wp)) { + // If signs are being displayed, add two spaces. + if (signcolumn_on(wp)) { len = wp->w_width - col; if (len > 0) { if (len > 2) { @@ -2209,8 +2215,8 @@ win_line ( ///< force wrapping int vcol_off = 0; ///< offset for concealed characters int did_wcol = false; - int match_conc = false; ///< cchar for match functions - int has_match_conc = false; ///< match wants to conceal + int match_conc = 0; ///< cchar for match functions + int has_match_conc = 0; ///< match wants to conceal int old_boguscols = 0; # define VCOL_HLC (vcol - vcol_off) # define FIX_FOR_BOGUSCOLS \ @@ -2403,11 +2409,14 @@ win_line ( if (v != 0) line_attr = sign_get_attr((int)v, TRUE); - /* Highlight the current line in the quickfix window. */ - if (bt_quickfix(wp->w_buffer) && qf_current_entry(wp) == lnum) - line_attr = hl_attr(HLF_L); - if (line_attr != 0) - area_highlighting = TRUE; + // Highlight the current line in the quickfix window. + if (bt_quickfix(wp->w_buffer) && qf_current_entry(wp) == lnum) { + line_attr = hl_attr(HLF_QFL); + } + + if (line_attr != 0) { + area_highlighting = true; + } line = ml_get_buf(wp->w_buffer, lnum, FALSE); ptr = line; @@ -2578,11 +2587,13 @@ win_line ( shl->startcol = MAXCOL; shl->endcol = MAXCOL; shl->attr_cur = 0; + shl->is_addpos = false; v = (long)(ptr - line); if (cur != NULL) { cur->pos.cur = 0; } - next_search_hl(wp, shl, lnum, (colnr_T)v, cur); + next_search_hl(wp, shl, lnum, (colnr_T)v, + shl == &search_hl ? NULL : cur); // Need to get the line again, a multi-line regexp may have made it // invalid. @@ -2624,7 +2635,12 @@ win_line ( * then. */ if (wp->w_p_cul && lnum == wp->w_cursor.lnum && !(wp == curwin && VIsual_active)) { - line_attr = hl_attr(HLF_CUL); + if (line_attr != 0 && !(State & INSERT) && bt_quickfix(wp->w_buffer) + && qf_current_entry(wp) == lnum) { + line_attr = hl_combine_attr(hl_attr(HLF_CUL), line_attr); + } else { + line_attr = hl_attr(HLF_CUL); + } area_highlighting = true; } @@ -2647,7 +2663,7 @@ win_line ( // Repeat for the whole displayed line. for (;; ) { - has_match_conc = false; + has_match_conc = 0; // Skip this quickly when working on the text. if (draw_state != WL_LINE) { if (draw_state == WL_CMDLINE - 1 && n_extra == 0) { @@ -2680,7 +2696,7 @@ win_line ( draw_state = WL_SIGN; /* Show the sign column when there are any signs in this * buffer or when using Netbeans. */ - if (draw_signcolumn(wp)) { + if (signcolumn_on(wp)) { int text_sign; /* Draw two cells with the sign value or blank. */ c_extra = ' '; @@ -2897,16 +2913,17 @@ win_line ( shl->attr_cur = shl->attr; if (cur != NULL && syn_name2id((char_u *)"Conceal") == cur->hlg_id) { - has_match_conc = true; + has_match_conc = v == (long)shl->startcol ? 2 : 1; match_conc = cur->conceal_char; } else { - has_match_conc = match_conc = false; + has_match_conc = match_conc = 0; } } else if (v == (long)shl->endcol) { shl->attr_cur = 0; prev_syntax_id = 0; - next_search_hl(wp, shl, lnum, (colnr_T)v, cur); + next_search_hl(wp, shl, lnum, (colnr_T)v, + shl == &search_hl ? NULL : cur); pos_inprogress = !(cur == NULL || cur->pos.cur == 0); /* Need to get the line again, a multi-line regexp @@ -3416,12 +3433,10 @@ win_line ( /* * Handling of non-printable characters. */ - if (!(chartab[c & 0xff] & CT_PRINT_CHAR)) { - /* - * when getting a character from the file, we may have to - * turn it into something else on the way to putting it - * into "ScreenLines". - */ + if (!vim_isprintc(c)) { + // when getting a character from the file, we may have to + // turn it into something else on the way to putting it + // into "ScreenLines". if (c == TAB && (!wp->w_p_list || lcs_tab1)) { int tab_len = 0; long vcol_adjusted = vcol; // removed showbreak length @@ -3626,11 +3641,11 @@ win_line ( if (wp->w_p_cole > 0 && (wp != curwin || lnum != wp->w_cursor.lnum || conceal_cursor_line(wp)) - && ((syntax_flags & HL_CONCEAL) != 0 || has_match_conc) + && ((syntax_flags & HL_CONCEAL) != 0 || has_match_conc > 0) && !(lnum_in_visual_area && vim_strchr(wp->w_p_cocu, 'v') == NULL)) { char_attr = conceal_attr; - if (prev_syntax_id != syntax_seqnr + if ((prev_syntax_id != syntax_seqnr || has_match_conc > 1) && (syn_get_sub_char() != NUL || match_conc || wp->w_p_cole == 1) && wp->w_p_cole != 3) { @@ -3743,18 +3758,18 @@ win_line ( if ((long)(wp->w_p_wrap ? wp->w_skipcol : wp->w_leftcol) > prevcol) ++prevcol; - /* Invert at least one char, used for Visual and empty line or - * highlight match at end of line. If it's beyond the last - * char on the screen, just overwrite that one (tricky!) Not - * needed when a '$' was displayed for 'list'. */ - prevcol_hl_flag = FALSE; - if (prevcol == (long)search_hl.startcol) - prevcol_hl_flag = TRUE; - else { + // Invert at least one char, used for Visual and empty line or + // highlight match at end of line. If it's beyond the last + // char on the screen, just overwrite that one (tricky!) Not + // needed when a '$' was displayed for 'list'. + prevcol_hl_flag = false; + if (!search_hl.is_addpos && prevcol == (long)search_hl.startcol) { + prevcol_hl_flag = true; + } else { cur = wp->w_match_head; while (cur != NULL) { - if (prevcol == (long)cur->hl.startcol) { - prevcol_hl_flag = TRUE; + if (!cur->hl.is_addpos && prevcol == (long)cur->hl.startcol) { + prevcol_hl_flag = true; break; } cur = cur->next; @@ -3804,10 +3819,13 @@ win_line ( shl_flag = TRUE; } else shl = &cur->hl; - if ((ptr - line) - 1 == (long)shl->startcol) + if ((ptr - line) - 1 == (long)shl->startcol + && (shl == &search_hl || !shl->is_addpos)) { char_attr = shl->attr; - if (shl != &search_hl && cur != NULL) + } + if (shl != &search_hl && cur != NULL) { cur = cur->next; + } } } ScreenAttrs[off] = char_attr; @@ -4821,15 +4839,12 @@ void win_redr_status(win_T *wp) wp->w_redr_status = FALSE; if (wp->w_status_height == 0) { - /* no status line, can only be last window */ - redraw_cmdline = TRUE; - } else if (!redrawing() - /* don't update status line when popup menu is visible and may be - * drawn over it */ - || pum_visible() - ) { - /* Don't redraw right now, do it later. */ - wp->w_redr_status = TRUE; + // no status line, can only be last window + redraw_cmdline = true; + } else if (!redrawing() || pum_drawn()) { + // Don't redraw right now, do it later. Don't update status line when + // popup menu is visible and may be drawn over it + wp->w_redr_status = true; } else if (*p_stl != NUL || *wp->w_p_stl != NUL) { /* redraw custom status line */ redraw_custom_statusline(wp); @@ -4897,7 +4912,7 @@ void win_redr_status(win_T *wp) screen_fill(row, row + 1, len + wp->w_wincol, this_ru_col + wp->w_wincol, fillchar, fillchar, attr); - if (get_keymap_str(wp, NameBuff, MAXPATHL) + if (get_keymap_str(wp, (char_u *)"<%s>", NameBuff, MAXPATHL) && this_ru_col - len > (int)(STRLEN(NameBuff) + 1)) screen_puts(NameBuff, row, (int)(this_ru_col - STRLEN(NameBuff) - 1 + wp->w_wincol), attr); @@ -4925,8 +4940,8 @@ void win_redr_status(win_T *wp) */ static void redraw_custom_statusline(win_T *wp) { - static int entered = FALSE; - int save_called_emsg = called_emsg; + static int entered = false; + int saved_did_emsg = did_emsg; /* When called recursively return. This can happen when the statusline * contains an expression that triggers a redraw. */ @@ -4934,18 +4949,18 @@ static void redraw_custom_statusline(win_T *wp) return; entered = TRUE; - called_emsg = FALSE; - win_redr_custom(wp, FALSE); - if (called_emsg) { - /* When there is an error disable the statusline, otherwise the - * display is messed up with errors and a redraw triggers the problem - * again and again. */ + did_emsg = false; + win_redr_custom(wp, false); + if (did_emsg) { + // When there is an error disable the statusline, otherwise the + // display is messed up with errors and a redraw triggers the problem + // again and again. set_string_option_direct((char_u *)"statusline", -1, (char_u *)"", OPT_FREE | (*wp->w_p_stl != NUL ? OPT_LOCAL : OPT_GLOBAL), SID_ERROR); } - called_emsg |= save_called_emsg; - entered = FALSE; + did_emsg |= saved_did_emsg; + entered = false; } /* @@ -4978,8 +4993,9 @@ int stl_connected(win_T *wp) int get_keymap_str ( win_T *wp, - char_u *buf, /* buffer for the result */ - int len /* length of buffer */ + char_u *fmt, // format string containing one %s item + char_u *buf, // buffer for the result + int len // length of buffer ) { char_u *p; @@ -5006,10 +5022,9 @@ get_keymap_str ( else p = (char_u *)"lang"; } - if ((int)(STRLEN(p) + 3) < len) - sprintf((char *)buf, "<%s>", p); - else + if (vim_snprintf((char *)buf, len, (char *)fmt, p) > len - 1) { buf[0] = NUL; + } xfree(s); } return buf[0] != NUL; @@ -5278,7 +5293,7 @@ void screen_puts_len(char_u *text, int textlen, int row, int col, int attr) int force_redraw_next = FALSE; int need_redraw; - const int l_has_mbyte = has_mbyte; + const bool l_has_mbyte = has_mbyte; const bool l_enc_utf8 = enc_utf8; const int l_enc_dbcs = enc_dbcs; @@ -5445,9 +5460,6 @@ void screen_puts_len(char_u *text, int textlen, int row, int col, int attr) /* If we detected the next character needs to be redrawn, but the text * doesn't extend up to there, update the character here. */ if (force_redraw_next && col < screen_Columns) { - if (l_enc_dbcs != 0 && dbcs_off2cells(off, max_off) > 1) - screen_char_2(off, row, col); - else screen_char(off, row, col); } } @@ -5546,8 +5558,9 @@ static void prepare_search_hl(win_T *wp, linenr_T lnum) // in progress n = 0; while (shl->first_lnum < lnum && (shl->rm.regprog != NULL - || (cur != NULL && pos_inprogress))) { - next_search_hl(wp, shl, shl->first_lnum, (colnr_T)n, cur); + || (cur != NULL && pos_inprogress))) { + next_search_hl(wp, shl, shl->first_lnum, (colnr_T)n, + shl == &search_hl ? NULL : cur); pos_inprogress = !(cur == NULL || cur->pos.cur == 0); if (shl->lnum != 0) { shl->first_lnum = shl->lnum @@ -5680,6 +5693,8 @@ next_search_hl ( } } +/// If there is a match fill "shl" and return one. +/// Return zero otherwise. static int next_search_hl_pos( match_T *shl, // points to a match @@ -5689,47 +5704,50 @@ next_search_hl_pos( ) { int i; - int bot = -1; + int found = -1; shl->lnum = 0; for (i = posmatch->cur; i < MAXPOSMATCH; i++) { - if (posmatch->pos[i].lnum == 0) { + llpos_T *pos = &posmatch->pos[i]; + + if (pos->lnum == 0) { break; } - if (posmatch->pos[i].col < mincol) { + if (pos->len == 0 && pos->col < mincol) { continue; } - if (posmatch->pos[i].lnum == lnum) { - if (bot != -1) { - // partially sort positions by column numbers - // on the same line - if (posmatch->pos[i].col < posmatch->pos[bot].col) { - llpos_T tmp = posmatch->pos[i]; + if (pos->lnum == lnum) { + if (found >= 0) { + // if this match comes before the one at "found" then swap + // them + if (pos->col < posmatch->pos[found].col) { + llpos_T tmp = *pos; - posmatch->pos[i] = posmatch->pos[bot]; - posmatch->pos[bot] = tmp; + *pos = posmatch->pos[found]; + posmatch->pos[found] = tmp; } } else { - bot = i; - shl->lnum = lnum; + found = i; } } } posmatch->cur = 0; - if (bot != -1) { - colnr_T start = posmatch->pos[bot].col == 0 - ? 0: posmatch->pos[bot].col - 1; - colnr_T end = posmatch->pos[bot].col == 0 - ? MAXCOL : start + posmatch->pos[bot].len; + if (found >= 0) { + colnr_T start = posmatch->pos[found].col == 0 + ? 0: posmatch->pos[found].col - 1; + colnr_T end = posmatch->pos[found].col == 0 + ? MAXCOL : start + posmatch->pos[found].len; + shl->lnum = lnum; shl->rm.startpos[0].lnum = 0; shl->rm.startpos[0].col = start; shl->rm.endpos[0].lnum = 0; shl->rm.endpos[0].col = end; - posmatch->cur = bot + 1; - return true; + shl->is_addpos = true; + posmatch->cur = found + 1; + return 1; } - return false; + return 0; } static void screen_start_highlight(int attr) @@ -6734,10 +6752,12 @@ int showmode(void) if (p_fkmap) MSG_PUTS_ATTR(farsi_text_5, attr); if (State & LANGMAP) { - if (curwin->w_p_arab) + if (curwin->w_p_arab) { MSG_PUTS_ATTR(_(" Arabic"), attr); - else - MSG_PUTS_ATTR(_(" (lang)"), attr); + } else if (get_keymap_str(curwin, (char_u *)" (%s)", + NameBuff, MAXPATHL)) { + MSG_PUTS_ATTR(NameBuff, attr); + } } if ((State & INSERT) && p_paste) MSG_PUTS_ATTR(_(" (paste)"), attr); @@ -6816,12 +6836,18 @@ void unshowmode(bool force) if (!redrawing() || (!force && char_avail() && !KeyTyped)) { redraw_cmdline = true; // delete mode later } else { + clearmode(); + } +} + +// Clear the mode message. +void clearmode(void) +{ msg_pos_mode(); if (Recording) { recording_mode(hl_attr(HLF_CM)); } msg_clr_eos(); - } } static void recording_mode(int attr) @@ -6871,16 +6897,17 @@ static void draw_tabline(void) /* Use the 'tabline' option if it's set. */ if (*p_tal != NUL) { - int save_called_emsg = called_emsg; + int saved_did_emsg = did_emsg; - /* Check for an error. If there is one we would loop in redrawing the - * screen. Avoid that by making 'tabline' empty. */ - called_emsg = FALSE; - win_redr_custom(NULL, FALSE); - if (called_emsg) + // Check for an error. If there is one we would loop in redrawing the + // screen. Avoid that by making 'tabline' empty. + did_emsg = false; + win_redr_custom(NULL, false); + if (did_emsg) { set_string_option_direct((char_u *)"tabline", -1, - (char_u *)"", OPT_FREE, SID_ERROR); - called_emsg |= save_called_emsg; + (char_u *)"", OPT_FREE, SID_ERROR); + } + did_emsg |= saved_did_emsg; } else { FOR_ALL_TABS(tp) { ++tabcount; @@ -7075,9 +7102,9 @@ void showruler(int always) { if (!always && !redrawing()) return; - if (pum_visible()) { - /* Don't redraw right now, do it later. */ - curwin->w_redr_status = TRUE; + if (pum_drawn()) { + // Don't redraw right now, do it later. + curwin->w_redr_status = true; return; } if ((*p_stl != NUL || *curwin->w_p_stl != NUL) && curwin->w_status_height) { @@ -7113,9 +7140,10 @@ static void win_redr_ruler(win_T *wp, int always) if (wp == lastwin && lastwin->w_status_height == 0) if (edit_submode != NULL) return; - /* Don't draw the ruler when the popup menu is visible, it may overlap. */ - if (pum_visible()) + // Don't draw the ruler when the popup menu is visible, it may overlap. + if (pum_drawn()) { return; + } if (*p_ruf) { int save_called_emsg = called_emsg; @@ -7365,7 +7393,7 @@ void screen_resize(int width, int height) redrawcmdline(); } else { update_topline(); - if (pum_visible()) { + if (pum_drawn()) { redraw_later(NOT_VALID); ins_compl_show_pum(); /* This includes the redraw. */ } else |