diff options
-rw-r--r-- | runtime/doc/options.txt | 2 | ||||
-rw-r--r-- | src/nvim/option.c | 6 | ||||
-rw-r--r-- | src/nvim/screen.c | 248 | ||||
-rw-r--r-- | src/nvim/testdir/test_signs.vim | 59 |
4 files changed, 218 insertions, 97 deletions
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index e1beea0fed..29f4abf250 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -5553,6 +5553,8 @@ A jump table for the options with a short description can be found at |Q_op|. "yes" always "yes:[1-9]" always, with fixed space for signs up to the given number (maximum 9), e.g. "yes:3" + "number" display signs in the 'number' column. If the number + column is not present, then behaves like 'auto'. *'smartcase'* *'scs'* *'nosmartcase'* *'noscs'* diff --git a/src/nvim/option.c b/src/nvim/option.c index d789ad3587..4157d28894 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -314,7 +314,7 @@ static char *(p_icm_values[]) = { "nosplit", "split", NULL }; static char *(p_scl_values[]) = { "yes", "no", "auto", "auto:1", "auto:2", "auto:3", "auto:4", "auto:5", "auto:6", "auto:7", "auto:8", "auto:9", "yes:1", "yes:2", "yes:3", "yes:4", "yes:5", "yes:6", "yes:7", "yes:8", - "yes:9", NULL }; + "yes:9", "number", NULL }; static char *(p_fdc_values[]) = { "auto:1", "auto:2", "auto:3", "auto:4", "auto:5", "auto:6", "auto:7", "auto:8", "auto:9", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", NULL }; @@ -7397,7 +7397,9 @@ int win_signcol_count(win_T *wp) int maximum = 1, needed_signcols; const char *scl = (const char *)wp->w_p_scl; - if (*scl == 'n') { + if (*scl == 'n' + && (*(scl + 1) == 'o' || (*(scl + 1) == 'u' + && (wp->w_p_nu || wp->w_p_rnu)))) { return 0; } needed_signcols = buf_signcols(wp->w_buffer); diff --git a/src/nvim/screen.c b/src/nvim/screen.c index ba52f5b489..e9df68f657 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -2816,6 +2816,7 @@ win_line ( for (;; ) { int has_match_conc = 0; ///< match wants to conceal bool did_decrement_ptr = false; + // Skip this quickly when working on the text. if (draw_state != WL_LINE) { if (draw_state == WL_CMDLINE - 1 && n_extra == 0) { @@ -2854,47 +2855,12 @@ win_line ( * buffer or when using Netbeans. */ int count = win_signcol_count(wp); if (count > 0) { - int text_sign; - // Draw cells with the sign value or blank. - c_extra = ' '; - c_final = NUL; - char_attr = win_hl_attr(wp, HLF_SC); - n_extra = win_signcol_width(wp); - - if (row == startrow + filler_lines && filler_todo <= 0) { - text_sign = buf_getsigntype(wp->w_buffer, lnum, SIGN_TEXT, - sign_idx, count); - if (text_sign != 0) { - p_extra = sign_get_text(text_sign); - if (p_extra != NULL) { - int symbol_blen = (int)STRLEN(p_extra); - - c_extra = NUL; - c_final = NUL; - - // TODO(oni-link): Is sign text already extended to - // full cell width? - assert((size_t)win_signcol_width(wp) - >= mb_string2cells(p_extra)); - // symbol(s) bytes + (filling spaces) (one byte each) - n_extra = symbol_blen + - (win_signcol_width(wp) - mb_string2cells(p_extra)); - - assert(sizeof(extra) > (size_t)symbol_blen); - memset(extra, ' ', sizeof(extra)); - memcpy(extra, p_extra, symbol_blen); - - p_extra = extra; - p_extra[n_extra] = NUL; - } - char_attr = sign_get_attr(text_sign, SIGN_TEXT); - } - } - - sign_idx++; - if (sign_idx < count) { - draw_state = WL_SIGN - 1; - } + get_sign_display_info( + false, wp, lnum, row, + startrow, filler_lines, filler_todo, count, + &c_extra, &c_final, extra, sizeof(extra), + &p_extra, &n_extra, + &char_attr, &draw_state, &sign_idx); } } @@ -2903,65 +2869,78 @@ win_line ( /* Display the absolute or relative line number. After the * first fill with blanks when the 'n' flag isn't in 'cpo' */ if ((wp->w_p_nu || wp->w_p_rnu) - && (row == startrow - + filler_lines + && (row == startrow + filler_lines || vim_strchr(p_cpo, CPO_NUMCOL) == NULL)) { - /* Draw the line number (empty space after wrapping). */ - if (row == startrow - + filler_lines - ) { - long num; - char *fmt = "%*ld "; - - if (wp->w_p_nu && !wp->w_p_rnu) - /* 'number' + 'norelativenumber' */ - num = (long)lnum; - else { - /* 'relativenumber', don't use negative numbers */ - num = labs((long)get_cursor_rel_lnum(wp, lnum)); - if (num == 0 && wp->w_p_nu && wp->w_p_rnu) { - /* 'number' + 'relativenumber' */ - num = lnum; - fmt = "%-*ld "; + // If 'signcolumn' is set to 'number' and a sign is present + // in 'lnum', then display the sign instead of the line + // number. + if (*wp->w_p_scl == 'n' && *(wp->w_p_scl + 1) == 'u' + && buf_findsign_id(wp->w_buffer, lnum, (char_u *)"*") != 0) { + int count = win_signcol_count(wp); + get_sign_display_info( + true, wp, lnum, row, + startrow, filler_lines, filler_todo, count, + &c_extra, &c_final, extra, sizeof(extra), + &p_extra, &n_extra, + &char_attr, &draw_state, &sign_idx); + } else { + if (row == startrow + filler_lines) { + // Draw the line number (empty space after wrapping). */ + long num; + char *fmt = "%*ld "; + + if (wp->w_p_nu && !wp->w_p_rnu) { + // 'number' + 'norelativenumber' + num = (long)lnum; + } else { + // 'relativenumber', don't use negative numbers + num = labs((long)get_cursor_rel_lnum(wp, lnum)); + if (num == 0 && wp->w_p_nu && wp->w_p_rnu) { + // 'number' + 'relativenumber' + num = lnum; + fmt = "%-*ld "; + } } - } - sprintf((char *)extra, fmt, - number_width(wp), num); - if (wp->w_skipcol > 0) - for (p_extra = extra; *p_extra == ' '; ++p_extra) - *p_extra = '-'; - if (wp->w_p_rl) { // reverse line numbers - // like rl_mirror(), but keep the space at the end - char_u *p2 = skiptowhite(extra) - 1; - for (char_u *p1 = extra; p1 < p2; p1++, p2--) { - const int t = *p1; - *p1 = *p2; - *p2 = t; + snprintf((char *)extra, sizeof(extra), + fmt, number_width(wp), num); + if (wp->w_skipcol > 0) { + for (p_extra = extra; *p_extra == ' '; p_extra++) { + *p_extra = '-'; + } } + if (wp->w_p_rl) { // reverse line numbers + // like rl_mirror(), but keep the space at the end + char_u *p2 = skiptowhite(extra) - 1; + for (char_u *p1 = extra; p1 < p2; p1++, p2--) { + const int t = *p1; + *p1 = *p2; + *p2 = t; + } + } + p_extra = extra; + c_extra = NUL; + c_final = NUL; + } else { + c_extra = ' '; + c_final = NUL; + } + n_extra = number_width(wp) + 1; + char_attr = win_hl_attr(wp, HLF_N); + + int num_sign = buf_getsigntype( + wp->w_buffer, lnum, SIGN_NUMHL, 0, 1); + if (num_sign != 0) { + // :sign defined with "numhl" highlight. + char_attr = sign_get_attr(num_sign, SIGN_NUMHL); + } else if ((wp->w_p_cul || wp->w_p_rnu) + && lnum == wp->w_cursor.lnum) { + // When 'cursorline' is set highlight the line number of + // the current line differently. + // TODO(vim): Can we use CursorLine instead of CursorLineNr + // when CursorLineNr isn't set? + char_attr = win_hl_attr(wp, HLF_CLN); } - p_extra = extra; - c_extra = NUL; - c_final = NUL; - } else { - c_extra = ' '; - c_final = NUL; - } - n_extra = number_width(wp) + 1; - char_attr = win_hl_attr(wp, HLF_N); - - int num_sign = buf_getsigntype(wp->w_buffer, lnum, SIGN_NUMHL, - 0, 1); - if (num_sign != 0) { - // :sign defined with "numhl" highlight. - char_attr = sign_get_attr(num_sign, SIGN_NUMHL); - } else if ((wp->w_p_cul || wp->w_p_rnu) - && lnum == wp->w_cursor.lnum) { - // When 'cursorline' is set highlight the line number of - // the current line differently. - // TODO(vim): Can we use CursorLine instead of CursorLineNr - // when CursorLineNr isn't set? - char_attr = win_hl_attr(wp, HLF_CLN); } } } @@ -4494,6 +4473,83 @@ void screen_adjust_grid(ScreenGrid **grid, int *row_off, int *col_off) } } +// Get information needed to display the sign in line 'lnum' in window 'wp'. +// If 'nrcol' is TRUE, the sign is going to be displayed in the number column. +// Otherwise the sign is going to be displayed in the sign column. +static void get_sign_display_info( + int nrcol, + win_T *wp, + linenr_T lnum, + int row, + int startrow, + int filler_lines, + int filler_todo, + int count, + int *c_extrap, + int *c_finalp, + char_u *extra, + size_t extra_size, + char_u **pp_extra, + int *n_extrap, + int *char_attrp, + int *draw_statep, + int *sign_idxp +) +{ + int text_sign; + + // Draw cells with the sign value or blank. + *c_extrap = ' '; + *c_finalp = NUL; + if (nrcol) { + *n_extrap = number_width(wp) + 1; + } else { + *char_attrp = win_hl_attr(wp, HLF_SC); + *n_extrap = win_signcol_width(wp); + } + + if (row == startrow + filler_lines && filler_todo <= 0) { + text_sign = buf_getsigntype(wp->w_buffer, lnum, SIGN_TEXT, + *sign_idxp, count); + if (text_sign != 0) { + *pp_extra = sign_get_text(text_sign); + if (*pp_extra != NULL) { + *c_extrap = NUL; + *c_finalp = NUL; + + if (nrcol) { + snprintf((char *)extra, extra_size, "%-*s ", + number_width(wp), *pp_extra); + *pp_extra = extra; + *n_extrap = (int)STRLEN(*pp_extra); + } else { + int symbol_blen = (int)STRLEN(*pp_extra); + + // TODO(oni-link): Is sign text already extended to + // full cell width? + assert((size_t)win_signcol_width(wp) >= mb_string2cells(*pp_extra)); + // symbol(s) bytes + (filling spaces) (one byte each) + *n_extrap = symbol_blen + + (win_signcol_width(wp) - mb_string2cells(*pp_extra)); + + assert(extra_size > (size_t)symbol_blen); + memset(extra, ' ', extra_size); + memcpy(extra, *pp_extra, symbol_blen); + + *pp_extra = extra; + (*pp_extra)[*n_extrap] = NUL; + } + } + *char_attrp = sign_get_attr(text_sign, SIGN_TEXT); + } + } + + (*sign_idxp)++; + if (*sign_idxp < count) { + *draw_statep = WL_SIGN - 1; + } +} + /* * Check whether the given character needs redrawing: @@ -7508,3 +7564,5 @@ win_T *get_win_by_grid_handle(handle_T handle) } return NULL; } + + diff --git a/src/nvim/testdir/test_signs.vim b/src/nvim/testdir/test_signs.vim index 8b1927e4f0..f89095ec5d 100644 --- a/src/nvim/testdir/test_signs.vim +++ b/src/nvim/testdir/test_signs.vim @@ -6,6 +6,8 @@ endif source screendump.vim +set noswapfile + func Test_sign() new call setline(1, ['a', 'b', 'c', 'd']) @@ -1742,3 +1744,60 @@ func Test_sign_cursor_position() call StopVimInTerminal(buf) call delete('XtestSigncolumn') endfunc + +" Return the 'len' characters in screen starting from (row,col) +func s:ScreenLine(row, col, len) + let s = '' + for i in range(a:len) + let s .= nr2char(screenchar(a:row, a:col + i)) + endfor + return s +endfunc + +" Test for 'signcolumn' set to 'number'. +func Test_sign_numcol() + new + call append(0, "01234") + " With 'signcolumn' set to 'number', make sure sign is displayed in the + " number column and line number is not displayed. + set numberwidth=2 + set number + set signcolumn=number + sign define sign1 text==> + sign place 10 line=1 name=sign1 + redraw! + call assert_equal("=> 01234", s:ScreenLine(1, 1, 8)) + + " With 'signcolumn' set to 'number', when there is no sign, make sure line + " number is displayed in the number column + sign unplace 10 + redraw! + call assert_equal("1 01234", s:ScreenLine(1, 1, 7)) + + " Disable number column. Check whether sign is displayed in the sign column + set numberwidth=4 + set nonumber + sign place 10 line=1 name=sign1 + redraw! + call assert_equal("=>01234", s:ScreenLine(1, 1, 7)) + + " Enable number column. Check whether sign is displayed in the number column + set number + redraw! + call assert_equal("=> 01234", s:ScreenLine(1, 1, 9)) + + " Disable sign column. Make sure line number is displayed + set signcolumn=no + redraw! + call assert_equal(" 1 01234", s:ScreenLine(1, 1, 9)) + + " Enable auto sign column. Make sure both sign and line number are displayed + set signcolumn=auto + redraw! + call assert_equal("=> 1 01234", s:ScreenLine(1, 1, 11)) + + sign undefine sign1 + set signcolumn& + set number& + enew! | close +endfunc |