diff options
Diffstat (limited to 'src/nvim/screen.c')
-rw-r--r-- | src/nvim/screen.c | 301 |
1 files changed, 247 insertions, 54 deletions
diff --git a/src/nvim/screen.c b/src/nvim/screen.c index ac07e60632..3c974f62bd 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -286,7 +286,8 @@ void update_curbuf(int type) void redraw_buf_status_later(buf_T *buf) { FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { - if (wp->w_buffer == buf && wp->w_status_height) { + if (wp->w_buffer == buf + && (wp->w_status_height || (wp == curwin && global_stl_height()))) { wp->w_redr_status = true; if (must_redraw < VALID) { must_redraw = VALID; @@ -316,6 +317,7 @@ void redraw_win_signcol(win_T *wp) int update_screen(int type) { static bool did_intro = false; + bool is_stl_global = global_stl_height() > 0; // Don't do anything if the screen structures are (not yet) valid. // A VimResized autocmd can invoke redrawing in the middle of a resize, @@ -398,10 +400,13 @@ int update_screen(int type) if (W_ENDROW(wp) > valid) { wp->w_redr_type = MAX(wp->w_redr_type, NOT_VALID); } - if (W_ENDROW(wp) + wp->w_status_height > valid) { + if (!is_stl_global && W_ENDROW(wp) + wp->w_status_height > valid) { wp->w_redr_status = true; } } + if (is_stl_global && Rows - p_ch - 1 > valid) { + curwin->w_redr_status = true; + } } msg_grid_set_pos(Rows-p_ch, false); msg_grid_invalid = false; @@ -423,13 +428,15 @@ int update_screen(int type) wp->w_redr_type = REDRAW_TOP; } else { wp->w_redr_type = NOT_VALID; - if (W_ENDROW(wp) + wp->w_status_height - <= msg_scrolled) { - wp->w_redr_status = TRUE; + if (!is_stl_global && W_ENDROW(wp) + wp->w_status_height <= msg_scrolled) { + wp->w_redr_status = true; } } } } + if (is_stl_global && Rows - p_ch - 1 <= msg_scrolled) { + curwin->w_redr_status = true; + } redraw_cmdline = true; redraw_tabline = true; } @@ -740,8 +747,11 @@ static void win_update(win_T *wp, DecorProviders *providers) wp->w_lines_valid = 0; } - // Window is zero-height: nothing to draw. + // Window is zero-height: Only need to draw the separator if (wp->w_grid.Rows == 0) { + // draw the horizontal separator below this window + draw_hsep_win(wp); + draw_sep_connectors_win(wp); wp->w_redr_type = 0; return; } @@ -749,7 +759,8 @@ static void win_update(win_T *wp, DecorProviders *providers) // Window is zero-width: Only need to draw the separator. if (wp->w_grid.Columns == 0) { // draw the vertical separator right of this window - draw_vsep_win(wp, 0); + draw_vsep_win(wp); + draw_sep_connectors_win(wp); wp->w_redr_type = 0; return; } @@ -1664,7 +1675,9 @@ static void win_update(win_T *wp, DecorProviders *providers) kvi_destroy(line_providers); if (wp->w_redr_type >= REDRAW_TOP) { - draw_vsep_win(wp, 0); + draw_vsep_win(wp); + draw_hsep_win(wp); + draw_sep_connectors_win(wp); } syn_set_timeout(NULL); @@ -4881,10 +4894,15 @@ void rl_mirror(char_u *str) */ void status_redraw_all(void) { - FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { - if (wp->w_status_height) { - wp->w_redr_status = true; - redraw_later(wp, VALID); + if (global_stl_height()) { + curwin->w_redr_status = true; + redraw_later(curwin, VALID); + } else { + FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { + if (wp->w_status_height) { + wp->w_redr_status = true; + redraw_later(wp, VALID); + } } } } @@ -4898,10 +4916,15 @@ void status_redraw_curbuf(void) /// Marks all status lines of the specified buffer for redraw. void status_redraw_buf(buf_T *buf) { - FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { - if (wp->w_status_height != 0 && wp->w_buffer == buf) { - wp->w_redr_status = true; - redraw_later(wp, VALID); + if (global_stl_height() != 0 && curwin->w_buffer == buf) { + curwin->w_redr_status = true; + redraw_later(curwin, VALID); + } else { + FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { + if (wp->w_status_height != 0 && wp->w_buffer == buf) { + wp->w_redr_status = true; + redraw_later(wp, VALID); + } } } } @@ -4943,10 +4966,8 @@ void win_redraw_last_status(const frame_T *frp) } } -/* - * Draw the verticap separator right of window "wp" starting with line "row". - */ -static void draw_vsep_win(win_T *wp, int row) +/// Draw the vertical separator right of window "wp" +static void draw_vsep_win(win_T *wp) { int hl; int c; @@ -4954,15 +4975,97 @@ static void draw_vsep_win(win_T *wp, int row) if (wp->w_vsep_width) { // draw the vertical separator right of this window c = fillchar_vsep(wp, &hl); - grid_fill(&default_grid, wp->w_winrow + row, W_ENDROW(wp), + grid_fill(&default_grid, wp->w_winrow, W_ENDROW(wp), W_ENDCOL(wp), W_ENDCOL(wp) + 1, c, ' ', hl); } } +/// Draw the horizontal separator below window "wp" +static void draw_hsep_win(win_T *wp) +{ + int hl; + int c; + + if (wp->w_hsep_height) { + // draw the horizontal separator below this window + c = fillchar_hsep(wp, &hl); + grid_fill(&default_grid, W_ENDROW(wp), W_ENDROW(wp) + 1, + wp->w_wincol, W_ENDCOL(wp), c, c, hl); + } +} -/* - * Get the length of an item as it will be shown in the status line. - */ +/// Get the separator connector for specified window corner of window "wp" +static int get_corner_sep_connector(win_T *wp, WindowCorner corner) +{ + // It's impossible for windows to be connected neither vertically nor horizontally + // So if they're not vertically connected, assume they're horizontally connected + if (vsep_connected(wp, corner)) { + if (hsep_connected(wp, corner)) { + return wp->w_p_fcs_chars.verthoriz; + } else if (corner == WC_TOP_LEFT || corner == WC_BOTTOM_LEFT) { + return wp->w_p_fcs_chars.vertright; + } else { + return wp->w_p_fcs_chars.vertleft; + } + } else if (corner == WC_TOP_LEFT || corner == WC_TOP_RIGHT) { + return wp->w_p_fcs_chars.horizdown; + } else { + return wp->w_p_fcs_chars.horizup; + } +} + +/// Draw seperator connecting characters on the corners of window "wp" +static void draw_sep_connectors_win(win_T *wp) +{ + // Don't draw separator connectors unless global statusline is enabled and the window has + // either a horizontal or vertical separator + if (global_stl_height() == 0 || !(wp->w_hsep_height == 1 || wp->w_vsep_width == 1)) { + return; + } + + int hl = win_hl_attr(wp, HLF_C); + + // Determine which edges of the screen the window is located on so we can avoid drawing separators + // on corners contained in those edges + bool win_at_top; + bool win_at_bottom = wp->w_hsep_height == 0; + bool win_at_left; + bool win_at_right = wp->w_vsep_width == 0; + frame_T *frp; + + for (frp = wp->w_frame; frp->fr_parent != NULL; frp = frp->fr_parent) { + if (frp->fr_parent->fr_layout == FR_COL && frp->fr_prev != NULL) { + break; + } + } + win_at_top = frp->fr_parent == NULL; + for (frp = wp->w_frame; frp->fr_parent != NULL; frp = frp->fr_parent) { + if (frp->fr_parent->fr_layout == FR_ROW && frp->fr_prev != NULL) { + break; + } + } + win_at_left = frp->fr_parent == NULL; + + // Draw the appropriate separator connector in every corner where drawing them is necessary + if (!(win_at_top || win_at_left)) { + grid_putchar(&default_grid, get_corner_sep_connector(wp, WC_TOP_LEFT), + wp->w_winrow - 1, wp->w_wincol - 1, hl); + } + if (!(win_at_top || win_at_right)) { + grid_putchar(&default_grid, get_corner_sep_connector(wp, WC_TOP_RIGHT), + wp->w_winrow - 1, W_ENDCOL(wp), hl); + } + if (!(win_at_bottom || win_at_left)) { + grid_putchar(&default_grid, get_corner_sep_connector(wp, WC_BOTTOM_LEFT), + W_ENDROW(wp), wp->w_wincol - 1, hl); + } + if (!(win_at_bottom || win_at_right)) { + grid_putchar(&default_grid, get_corner_sep_connector(wp, WC_BOTTOM_RIGHT), + W_ENDROW(wp), W_ENDCOL(wp), hl); + } +} + +/// Get the length of an item as it will be shown in the status line. static int status_match_len(expand_T *xp, char_u *s) { int len = 0; @@ -5163,7 +5266,7 @@ void win_redr_status_matches(expand_T *xp, int num_matches, char_u **matches, in // Create status line if needed by setting 'laststatus' to 2. // Set 'winminheight' to zero to avoid that the window is // resized. - if (lastwin->w_status_height == 0) { + if (lastwin->w_status_height == 0 && global_stl_height() == 0) { save_p_ls = p_ls; save_p_wmh = p_wmh; p_ls = 2; @@ -5199,12 +5302,15 @@ void win_redr_status_matches(expand_T *xp, int num_matches, char_u **matches, in static void win_redr_status(win_T *wp) { int row; + int col; char_u *p; int len; int fillchar; int attr; + int width; int this_ru_col; - static int busy = FALSE; + bool is_stl_global = global_stl_height() > 0; + static int busy = false; // May get here recursively when 'statusline' (indirectly) // invokes ":redrawstatus". Simply ignore the call then. @@ -5215,9 +5321,9 @@ static void win_redr_status(win_T *wp) } busy = true; - wp->w_redr_status = FALSE; - if (wp->w_status_height == 0) { - // no status line, can only be last window + wp->w_redr_status = false; + if (wp->w_status_height == 0 && !(is_stl_global && wp == curwin)) { + // no status line, either global statusline is enabled or the window is a last window redraw_cmdline = true; } else if (!redrawing()) { // Don't redraw right now, do it later. Don't update status line when @@ -5228,6 +5334,7 @@ static void win_redr_status(win_T *wp) redraw_custom_statusline(wp); } else { fillchar = fillchar_status(&attr, wp); + width = is_stl_global ? Columns : wp->w_width; get_trans_bufname(wp->w_buffer); p = NameBuff; @@ -5256,9 +5363,9 @@ static void win_redr_status(win_T *wp) // len += (int)STRLEN(p + len); // dead assignment } - this_ru_col = ru_col - (Columns - wp->w_width); - if (this_ru_col < (wp->w_width + 1) / 2) { - this_ru_col = (wp->w_width + 1) / 2; + this_ru_col = ru_col - (Columns - width); + if (this_ru_col < (width + 1) / 2) { + this_ru_col = (width + 1) / 2; } if (this_ru_col <= 1) { p = (char_u *)"<"; // No room for file name! @@ -5283,10 +5390,11 @@ static void win_redr_status(win_T *wp) } } - row = W_ENDROW(wp); - grid_puts(&default_grid, p, row, wp->w_wincol, attr); - grid_fill(&default_grid, row, row + 1, len + wp->w_wincol, - this_ru_col + wp->w_wincol, fillchar, fillchar, attr); + row = is_stl_global ? (Rows - p_ch - 1) : W_ENDROW(wp); + col = is_stl_global ? 0 : wp->w_wincol; + grid_puts(&default_grid, p, row, col, attr); + grid_fill(&default_grid, row, row + 1, len + col, + this_ru_col + col, fillchar, fillchar, attr); if (get_keymap_str(wp, (char_u *)"<%s>", NameBuff, MAXPATHL) && this_ru_col - len > (int)(STRLEN(NameBuff) + 1)) { @@ -5365,6 +5473,76 @@ bool stl_connected(win_T *wp) return false; } +/// Check if horizontal separator of window "wp" at specified window corner is connected to the +/// horizontal separator of another window +/// Assumes global statusline is enabled +static bool hsep_connected(win_T *wp, WindowCorner corner) +{ + bool before = (corner == WC_TOP_LEFT || corner == WC_BOTTOM_LEFT); + int sep_row = (corner == WC_TOP_LEFT || corner == WC_TOP_RIGHT) + ? wp->w_winrow - 1 : W_ENDROW(wp); + frame_T *fr = wp->w_frame; + + while (fr->fr_parent != NULL) { + if (fr->fr_parent->fr_layout == FR_ROW && (before ? fr->fr_prev : fr->fr_next) != NULL) { + fr = before ? fr->fr_prev : fr->fr_next; + break; + } + fr = fr->fr_parent; + } + if (fr->fr_parent == NULL) { + return false; + } + while (fr->fr_layout != FR_LEAF) { + fr = fr->fr_child; + if (fr->fr_parent->fr_layout == FR_ROW && before) { + while (fr->fr_next != NULL) { + fr = fr->fr_next; + } + } else { + while (fr->fr_next != NULL && frame2win(fr)->w_winrow + fr->fr_height < sep_row) { + fr = fr->fr_next; + } + } + } + + return (sep_row == fr->fr_win->w_winrow - 1 || sep_row == W_ENDROW(fr->fr_win)); +} + +/// Check if vertical separator of window "wp" at specified window corner is connected to the +/// vertical separator of another window +static bool vsep_connected(win_T *wp, WindowCorner corner) +{ + bool before = (corner == WC_TOP_LEFT || corner == WC_TOP_RIGHT); + int sep_col = (corner == WC_TOP_LEFT || corner == WC_BOTTOM_LEFT) + ? wp->w_wincol - 1 : W_ENDCOL(wp); + frame_T *fr = wp->w_frame; + + while (fr->fr_parent != NULL) { + if (fr->fr_parent->fr_layout == FR_COL && (before ? fr->fr_prev : fr->fr_next) != NULL) { + fr = before ? fr->fr_prev : fr->fr_next; + break; + } + fr = fr->fr_parent; + } + if (fr->fr_parent == NULL) { + return false; + } + while (fr->fr_layout != FR_LEAF) { + fr = fr->fr_child; + if (fr->fr_parent->fr_layout == FR_COL && before) { + while (fr->fr_next != NULL) { + fr = fr->fr_next; + } + } else { + while (fr->fr_next != NULL && frame2win(fr)->w_wincol + fr->fr_width < sep_col) { + fr = fr->fr_next; + } + } + } + + return (sep_col == fr->fr_win->w_wincol - 1 || sep_col == W_ENDCOL(fr->fr_win)); +} /// Get the value to show for the language mappings, active 'keymap'. /// @@ -5431,6 +5609,7 @@ static void win_redr_custom(win_T *wp, bool draw_ruler) int use_sandbox = false; win_T *ewp; int p_crb_save; + bool is_stl_global = global_stl_height() > 0; ScreenGrid *grid = &default_grid; @@ -5452,9 +5631,9 @@ static void win_redr_custom(win_T *wp, bool draw_ruler) maxwidth = Columns; use_sandbox = was_set_insecurely(wp, "tabline", 0); } else { - row = W_ENDROW(wp); + row = is_stl_global ? (Rows - p_ch - 1) : W_ENDROW(wp); fillchar = fillchar_status(&attr, wp); - maxwidth = wp->w_width; + maxwidth = is_stl_global ? Columns : wp->w_width; if (draw_ruler) { stl = p_ruf; @@ -5472,12 +5651,12 @@ static void win_redr_custom(win_T *wp, bool draw_ruler) stl = p_ruf; } } - col = ru_col - (Columns - wp->w_width); - if (col < (wp->w_width + 1) / 2) { - col = (wp->w_width + 1) / 2; + col = ru_col - (Columns - maxwidth); + if (col < (maxwidth + 1) / 2) { + col = (maxwidth + 1) / 2; } - maxwidth = wp->w_width - col; - if (!wp->w_status_height) { + maxwidth = maxwidth - col; + if (!wp->w_status_height && !is_stl_global) { grid = &msg_grid_adj; row = Rows - 1; maxwidth--; // writing in last column may cause scrolling @@ -5495,7 +5674,7 @@ static void win_redr_custom(win_T *wp, bool draw_ruler) use_sandbox = was_set_insecurely(wp, "statusline", *wp->w_p_stl == NUL ? 0 : OPT_LOCAL); } - col += wp->w_wincol; + col += is_stl_global ? 0 : wp->w_wincol; } if (maxwidth <= 0) { @@ -7077,10 +7256,10 @@ int showmode(void) clear_showcmd(); } - // If the last window has no status line, the ruler is after the mode - // message and must be redrawn + // If the last window has no status line and global statusline is disabled, + // the ruler is after the mode message and must be redrawn win_T *last = lastwin_nofloating(); - if (redrawing() && last->w_status_height == 0) { + if (redrawing() && last->w_status_height == 0 && global_stl_height() == 0) { win_redr_ruler(last, true); } redraw_cmdline = false; @@ -7395,16 +7574,22 @@ int fillchar_status(int *attr, win_T *wp) return '='; } -/* - * Get the character to use in a separator between vertically split windows. - * Get its attributes in "*attr". - */ +/// Get the character to use in a separator between vertically split windows. +/// Get its attributes in "*attr". static int fillchar_vsep(win_T *wp, int *attr) { *attr = win_hl_attr(wp, HLF_C); return wp->w_p_fcs_chars.vert; } +/// Get the character to use in a separator between horizontally split windows. +/// Get its attributes in "*attr". +static int fillchar_hsep(win_T *wp, int *attr) +{ + *attr = win_hl_attr(wp, HLF_C); + return wp->w_p_fcs_chars.horiz; +} + /* * Return TRUE if redrawing should currently be done. */ @@ -7430,7 +7615,8 @@ void showruler(bool always) if (!always && !redrawing()) { return; } - if ((*p_stl != NUL || *curwin->w_p_stl != NUL) && curwin->w_status_height) { + if ((*p_stl != NUL || *curwin->w_p_stl != NUL) + && (curwin->w_status_height || global_stl_height())) { redraw_custom_statusline(curwin); } else { win_redr_ruler(curwin, always); @@ -7449,6 +7635,7 @@ void showruler(bool always) static void win_redr_ruler(win_T *wp, bool always) { + bool is_stl_global = global_stl_height() > 0; static bool did_show_ext_ruler = false; // If 'ruler' off or redrawing disabled, don't do anything @@ -7466,7 +7653,7 @@ static void win_redr_ruler(win_T *wp, bool always) // Don't draw the ruler while doing insert-completion, it might overwrite // the (long) mode message. - if (wp == lastwin && lastwin->w_status_height == 0) { + if (wp == lastwin && lastwin->w_status_height == 0 && !is_stl_global) { if (edit_submode != NULL) { return; } @@ -7521,6 +7708,12 @@ static void win_redr_ruler(win_T *wp, bool always) off = wp->w_wincol; width = wp->w_width; part_of_status = true; + } else if (is_stl_global) { + row = Rows - p_ch - 1; + fillchar = fillchar_status(&attr, wp); + off = 0; + width = Columns; + part_of_status = true; } else { row = Rows - 1; fillchar = ' '; @@ -7560,7 +7753,7 @@ static void win_redr_ruler(win_T *wp, bool always) int i = (int)STRLEN(buffer); get_rel_pos(wp, buffer + i + 1, RULER_BUF_LEN - i - 1); int o = i + vim_strsize(buffer + i + 1); - if (wp->w_status_height == 0) { // can't use last char of screen + if (wp->w_status_height == 0 && !is_stl_global) { // can't use last char of screen o++; } int this_ru_col = ru_col - (Columns - width); |