Skip to content

Commit

Permalink
vim-patch:8.1.1564: sign column takes up space
Browse files Browse the repository at this point in the history
Problem:    Sign column takes up space.  (Adam Stankiewicz)
Solution:   Optionally put signs in the number column. (Yegappan Lakshmanan,
            closes vim/vim#4555, closes vim/vim#4515)
vim/vim@394c5d8
  • Loading branch information
Shougo committed Jul 23, 2020
1 parent 326b87f commit d3eddcf
Show file tree
Hide file tree
Showing 4 changed files with 218 additions and 97 deletions.
2 changes: 2 additions & 0 deletions runtime/doc/options.txt
Expand Up @@ -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'*
Expand Down
6 changes: 4 additions & 2 deletions src/nvim/option.c
Expand Up @@ -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 };
Expand Down Expand Up @@ -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);
Expand Down
248 changes: 153 additions & 95 deletions src/nvim/screen.c
Expand Up @@ -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) {
Expand Down Expand Up @@ -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);
}
}

Expand All @@ -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);
}
}
}
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -7508,3 +7564,5 @@ win_T *get_win_by_grid_handle(handle_T handle)
}
return NULL;
}


59 changes: 59 additions & 0 deletions src/nvim/testdir/test_signs.vim
Expand Up @@ -6,6 +6,8 @@ endif

source screendump.vim

set noswapfile

func Test_sign()
new
call setline(1, ['a', 'b', 'c', 'd'])
Expand Down Expand Up @@ -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

0 comments on commit d3eddcf

Please sign in to comment.