signs: support multiple columns #9295

closes #990
closes #9295

- Support for multiple auto-adjusted sign columns.
  With this change, having more than one sign on a line, and with the
  'auto' setting on 'signcolumn', extra columns will shown automatically
  to accomodate all the existing signs.

  For example, suppose we have this view:

   5147             }
   5148
   5149             return sign->typenr;
   5150         }
   5151     }
   5152     return 0;
   5153 }
   5154

  We have GitGutter installed, so it tells us about modified lines that
  are not commmited. So let's change line 5152:

     5147             }
     5148
     5149             return sign->typenr;
     5150         }
     5151     }
   ~ 5152     return 0;
     5153 }
     5154

  Now we add a mark over line 5152 using 'ma' in normal mode:

      5147             }
      5148
      5149             return sign->typenr;
      5150         }
      5151     }
  a ~ 5152     return 0;
      5153 }
      5154

  Previously, Vim/Nvim would have picked only one of the signs,
  because there was no support for having multiple signs in a line.

- Remove signs from deleted lines.
  Suppose we have highlights on a group of lines and we delete them:

   +     6 use std::ops::Deref;
   --+   7 use std::borrow::Cow;
   --+   8 use std::io::{Cursor};
         9 use proc_macro2::TokenStream;
        10 use syn::export::ToTokens;
   --+  11 use std::io::Write;
   >>   12 use std::ops::Deref;

  Without this change, these signs will momentarily accumulate in
  the sign column until the plugins wake up to refresh them.

  + --+ --+ --+ >>  6

  Discussion: It may be better to extend the API a bit and allow this
  to happen for only certain types of signs. For example, VIM marks
  and vim-gitgutter removal signs may want to be presreved, unlike
  line additions and linter highlights.

- 'signcolumn': support 'auto:NUM' and 'yes:NUM' settings
- sort signs according to id, from lowest to highest. If you have
  git-gutter, vim-signature, and ALE, it would appear in this order:
  git-gutter - vim-signature - ALE.
- recalculate size before screen update
- If no space for all signs, prefer the higher ids (while keeping the
  rendering order from low to high).
- Prevent duplicate signs. Duplicate signs were invisible to the user,
  before using our extended non-standard signcolumn settings.
- multi signcols: fix bug related to wrapped lines.
  In wrapped lines, the wrapped parts of a line did not include the extra
  columns if they existed. The result was a misdrawing of the wrapped
  parts. Fix the issue by:
    1. initializing the signcol counter to 0 when we are on a wrap boundary
    2. allowing for the draw of spaces in that case.
This commit is contained in:
Dan Aloni
2019-03-25 02:16:58 +01:00
committed by Justin M. Keyes
parent f705ed22fd
commit 36762a00a8
10 changed files with 348 additions and 55 deletions

View File

@@ -621,6 +621,11 @@ static void win_update(win_T *wp)
linenr_T mod_bot = 0;
int save_got_int;
// If we can compute a change in the automatic sizing of the sign column
// under 'signcolumn=auto:X' and signs currently placed in the buffer, better
// figuring it out here so we can redraw the entire screen for it.
buf_signcols(buf);
type = wp->w_redr_type;
win_grid_alloc(wp);
@@ -1568,8 +1573,9 @@ static void win_draw_end(win_T *wp, int c1, int c2, int row, int endrow, hlf_T h
wp->w_grid.Columns, ' ', ' ', win_hl_attr(wp, HLF_FC));
}
if (signcolumn_on(wp)) {
int nn = n + win_signcol_width(wp);
int count = win_signcol_count(wp);
if (count > 0) {
int nn = n + win_signcol_width(wp) * count;
// draw the sign column left of the fold column
if (nn > wp->w_grid.Columns) {
@@ -1607,8 +1613,9 @@ static void win_draw_end(win_T *wp, int c1, int c2, int row, int endrow, hlf_T h
n = nn;
}
if (signcolumn_on(wp)) {
int nn = n + win_signcol_width(wp);
int count = win_signcol_count(wp);
if (count > 0) {
int nn = n + win_signcol_width(wp) * count;
// draw the sign column after the fold column
if (nn > wp->w_grid.Columns) {
@@ -1773,10 +1780,10 @@ static void fold_line(win_T *wp, long fold_count, foldinfo_T *foldinfo, linenr_T
RL_MEMSET(col, win_hl_attr(wp, HLF_FL), wp->w_grid.Columns - col);
// If signs are being displayed, add spaces.
if (signcolumn_on(wp)) {
if (win_signcol_count(wp) > 0) {
len = wp->w_grid.Columns - col;
if (len > 0) {
int len_max = win_signcol_width(wp);
int len_max = win_signcol_width(wp) * win_signcol_count(wp);
if (len > len_max) {
len = len_max;
}
@@ -2404,7 +2411,7 @@ win_line (
}
// If this line has a sign with line highlighting set line_attr.
v = buf_getsigntype(wp->w_buffer, lnum, SIGN_LINEHL);
v = buf_getsigntype(wp->w_buffer, lnum, SIGN_LINEHL, 0, 1);
if (v != 0) {
line_attr = sign_get_attr((int)v, SIGN_LINEHL);
}
@@ -2654,6 +2661,7 @@ win_line (
extra_check = true;
}
int sign_idx = 0;
// Repeat for the whole displayed line.
for (;; ) {
has_match_conc = 0;
@@ -2694,7 +2702,8 @@ win_line (
draw_state = WL_SIGN;
/* Show the sign column when there are any signs in this
* buffer or when using Netbeans. */
if (signcolumn_on(wp)) {
int count = win_signcol_count(wp);
if (count > 0) {
int text_sign;
// Draw cells with the sign value or blank.
c_extra = ' ';
@@ -2703,7 +2712,8 @@ win_line (
n_extra = win_signcol_width(wp);
if (row == startrow + filler_lines && filler_todo <= 0) {
text_sign = buf_getsigntype(wp->w_buffer, lnum, SIGN_TEXT);
text_sign = buf_getsigntype(wp->w_buffer, lnum, SIGN_TEXT,
sign_idx, count);
if (text_sign != 0) {
p_extra = sign_get_text(text_sign);
int symbol_blen = (int)STRLEN(p_extra);
@@ -2721,6 +2731,11 @@ win_line (
char_attr = sign_get_attr(text_sign, SIGN_TEXT);
}
}
sign_idx++;
if (sign_idx < count) {
draw_state = WL_SIGN - 1;
}
}
}
@@ -2769,7 +2784,8 @@ win_line (
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);
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);
@@ -2856,6 +2872,7 @@ win_line (
}
if (draw_state == WL_LINE - 1 && n_extra == 0) {
sign_idx = 0;
draw_state = WL_LINE;
if (saved_n_extra) {
/* Continue item from end of wrapped line. */