aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/window.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/window.c')
-rw-r--r--src/nvim/window.c227
1 files changed, 175 insertions, 52 deletions
diff --git a/src/nvim/window.c b/src/nvim/window.c
index 39346faa14..2d995af00d 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -6,11 +6,14 @@
#include <stdbool.h>
#include "nvim/api/private/helpers.h"
+#include "nvim/api/vim.h"
+#include "nvim/arglist.h"
#include "nvim/ascii.h"
#include "nvim/buffer.h"
#include "nvim/charset.h"
#include "nvim/cursor.h"
#include "nvim/diff.h"
+#include "nvim/drawscreen.h"
#include "nvim/edit.h"
#include "nvim/eval.h"
#include "nvim/eval/vars.h"
@@ -25,7 +28,9 @@
#include "nvim/garray.h"
#include "nvim/getchar.h"
#include "nvim/globals.h"
+#include "nvim/grid.h"
#include "nvim/hashtab.h"
+#include "nvim/highlight.h"
#include "nvim/main.h"
#include "nvim/mapping.h"
#include "nvim/mark.h"
@@ -43,7 +48,6 @@
#include "nvim/plines.h"
#include "nvim/quickfix.h"
#include "nvim/regexp.h"
-#include "nvim/screen.h"
#include "nvim/search.h"
#include "nvim/state.h"
#include "nvim/strings.h"
@@ -122,7 +126,7 @@ void do_window(int nchar, long Prenum, int xchar)
{
long Prenum1;
win_T *wp;
- char_u *ptr;
+ char *ptr;
linenr_T lnum = -1;
int type = FIND_DEFINE;
size_t len;
@@ -483,14 +487,14 @@ newwindow:
wingotofile:
CHECK_CMDWIN;
- ptr = grab_file_name(Prenum1, &lnum);
+ ptr = (char *)grab_file_name(Prenum1, &lnum);
if (ptr != NULL) {
tabpage_T *oldtab = curtab;
win_T *oldwin = curwin;
setpcmark();
if (win_split(0, 0) == OK) {
RESET_BINDING(curwin);
- if (do_ecmd(0, (char *)ptr, NULL, NULL, ECMD_LASTL, ECMD_HIDE, NULL) == FAIL) {
+ if (do_ecmd(0, ptr, NULL, NULL, ECMD_LASTL, ECMD_HIDE, NULL) == FAIL) {
// Failed to open the file, close the window opened for it.
win_close(curwin, false, false);
goto_tabpage_win(oldtab, oldwin);
@@ -518,9 +522,9 @@ wingotofile:
}
// Make a copy, if the line was changed it will be freed.
- ptr = vim_strnsave(ptr, len);
+ ptr = xstrnsave(ptr, len);
- find_pattern_in_path(ptr, 0, len, true, Prenum == 0,
+ find_pattern_in_path((char_u *)ptr, 0, len, true, Prenum == 0,
type, Prenum1, ACTION_SPLIT, 1, MAXLNUM);
xfree(ptr);
curwin->w_set_curswant = true;
@@ -698,14 +702,14 @@ win_T *win_new_float(win_T *wp, bool last, FloatConfig fconfig, Error *err)
win_remove(wp, NULL);
win_append(lastwin_nofloating(), wp);
}
- wp->w_floating = 1;
+ wp->w_floating = true;
wp->w_status_height = 0;
wp->w_winbar_height = 0;
wp->w_hsep_height = 0;
wp->w_vsep_width = 0;
win_config_float(wp, fconfig);
- win_set_inner_size(wp);
+ win_set_inner_size(wp, true);
wp->w_pos_changed = true;
redraw_later(wp, VALID);
return wp;
@@ -728,13 +732,15 @@ void win_set_minimal_style(win_T *wp)
: concat_str(old, (char_u *)",eob: "));
free_string_option(old);
}
- if (wp->w_hl_ids[HLF_EOB] != -1) {
- char_u *old = wp->w_p_winhl;
- wp->w_p_winhl = ((*old == NUL)
- ? (char_u *)xstrdup("EndOfBuffer:")
- : concat_str(old, (char_u *)",EndOfBuffer:"));
- free_string_option(old);
- }
+
+ // TODO(bfredl): this could use a highlight namespace directly,
+ // and avoid pecularities around window options
+ char_u *old = wp->w_p_winhl;
+ wp->w_p_winhl = ((*old == NUL)
+ ? (char_u *)xstrdup("EndOfBuffer:")
+ : concat_str(old, (char_u *)",EndOfBuffer:"));
+ free_string_option(old);
+ parse_winhl_opt(wp);
// signcolumn: use 'auto'
if (wp->w_p_scl[0] != 'a' || STRLEN(wp->w_p_scl) >= 8) {
@@ -789,7 +795,7 @@ void win_config_float(win_T *wp, FloatConfig fconfig)
wp->w_width = MIN(wp->w_width, Columns - win_border_width(wp));
}
- win_set_inner_size(wp);
+ win_set_inner_size(wp, true);
must_redraw = MAX(must_redraw, VALID);
wp->w_pos_changed = true;
@@ -1270,7 +1276,7 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
wp->w_floating = false;
// non-floating window doesn't store float config or have a border.
wp->w_float_config = FLOAT_CONFIG_INIT;
- memset(wp->w_border_adj, 0, sizeof(wp->w_border_adj));
+ CLEAR_FIELD(wp->w_border_adj);
}
/*
@@ -1670,7 +1676,7 @@ int win_count(void)
int count = 0;
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
- ++count;
+ count++;
}
return count;
}
@@ -2459,7 +2465,7 @@ void close_windows(buf_T *buf, bool keep_curwin)
tabpage_T *tp, *nexttp;
int h = tabline_height();
- ++RedrawingDisabled;
+ RedrawingDisabled++;
// Start from lastwin to close floating windows with the same buffer first.
// When the autocommand window is involved win_close() may need to print an error message.
@@ -2496,7 +2502,7 @@ void close_windows(buf_T *buf, bool keep_curwin)
}
}
- --RedrawingDisabled;
+ RedrawingDisabled--;
redraw_tabline = true;
if (h != tabline_height()) {
@@ -3825,7 +3831,7 @@ static int frame_minwidth(frame_T *topfrp, win_T *next_curwin)
m = (int)p_wmw + topfrp->fr_win->w_vsep_width;
// Current window is minimal one column wide
if (p_wmw == 0 && topfrp->fr_win == curwin && next_curwin == NULL) {
- ++m;
+ m++;
}
}
} else if (topfrp->fr_layout == FR_COL) {
@@ -4098,7 +4104,7 @@ int win_new_tabpage(int after, char_u *filename)
n = 2;
for (tp = first_tabpage; tp->tp_next != NULL
&& n < after; tp = tp->tp_next) {
- ++n;
+ n++;
}
}
newtp->tp_next = tp->tp_next;
@@ -4244,7 +4250,7 @@ tabpage_T *find_tabpage(int n)
int i = 1;
for (tp = first_tabpage; tp != NULL && i != n; tp = tp->tp_next) {
- ++i;
+ i++;
}
return tp;
}
@@ -4259,7 +4265,7 @@ int tabpage_index(tabpage_T *ftp)
tabpage_T *tp;
for (tp = first_tabpage; tp != NULL && tp != ftp; tp = tp->tp_next) {
- ++i;
+ i++;
}
return i;
}
@@ -4521,7 +4527,7 @@ void tabpage_move(int nr)
}
for (tp = first_tabpage; tp->tp_next != NULL && n < nr; tp = tp->tp_next) {
- ++n;
+ n++;
}
if (tp == curtab || (nr > 0 && tp->tp_next != NULL
@@ -4868,10 +4874,17 @@ static void win_enter_ext(win_T *const wp, const int flags)
redraw_later(curwin, VALID); // causes status line redraw
}
- if (HL_ATTR(HLF_INACTIVE)
- || (prevwin && prevwin->w_hl_ids[HLF_INACTIVE])
- || curwin->w_hl_ids[HLF_INACTIVE]) {
- redraw_all_later(NOT_VALID);
+ // change background color according to NormalNC,
+ // but only if actually defined (otherwise no extra redraw)
+ if (curwin->w_hl_attr_normal != curwin->w_hl_attr_normalnc) {
+ // TODO(bfredl): eventually we should be smart enough
+ // to only recompose the window, not redraw it.
+ redraw_later(curwin, NOT_VALID);
+ }
+ if (prevwin) {
+ if (prevwin->w_hl_attr_normal != prevwin->w_hl_attr_normalnc) {
+ redraw_later(prevwin, NOT_VALID);
+ }
}
// set window height to desired minimal value
@@ -5040,6 +5053,8 @@ static win_T *win_alloc(win_T *after, bool hidden)
new_wp->w_float_config = FLOAT_CONFIG_INIT;
new_wp->w_viewport_invalid = true;
+ new_wp->w_ns_hl = -1;
+
// use global option for global-local options
new_wp->w_p_so = -1;
new_wp->w_p_siso = -1;
@@ -5180,7 +5195,7 @@ void win_free_grid(win_T *wp, bool reinit)
grid_free(&wp->w_grid_alloc);
if (reinit) {
// if a float is turned into a split, the grid data structure will be reused
- memset(&wp->w_grid_alloc, 0, sizeof(wp->w_grid_alloc));
+ CLEAR_FIELD(wp->w_grid_alloc);
}
}
@@ -5556,7 +5571,7 @@ static void frame_setheight(frame_T *curfrp, int height)
}
if (curfrp->fr_parent == NULL) {
- // topframe: can only change the command line
+ // topframe: can only change the command line height
if (height > ROWS_AVAIL) {
// If height is greater than the available space, try to create space for
// the frame by reducing 'cmdheight' if possible, while making sure
@@ -5919,6 +5934,13 @@ void win_drag_status_line(win_T *dragwin, int offset)
int row;
bool up; // if true, drag status line up, otherwise down
int n;
+ static bool p_ch_was_zero = false;
+
+ // If the user explicitly set 'cmdheight' to zero, then allow for dragging
+ // the status line making it zero again.
+ if (p_ch == 0) {
+ p_ch_was_zero = true;
+ }
fr = dragwin->w_frame;
curfr = fr;
@@ -5969,6 +5991,8 @@ void win_drag_status_line(win_T *dragwin, int offset)
room = Rows - cmdline_row;
if (curfr->fr_next != NULL) {
room -= (int)p_ch + global_stl_height();
+ } else if (!p_ch_was_zero) {
+ room--;
}
if (room < 0) {
room = 0;
@@ -6024,7 +6048,7 @@ void win_drag_status_line(win_T *dragwin, int offset)
clear_cmdline = true;
}
cmdline_row = row;
- p_ch = MAX(Rows - cmdline_row, 0);
+ p_ch = MAX(Rows - cmdline_row, p_ch_was_zero ? 0 : 1);
curtab->tp_ch_used = p_ch;
redraw_all_later(SOME_VALID);
showmode();
@@ -6167,7 +6191,7 @@ void win_new_height(win_T *wp, int height)
wp->w_height = height;
wp->w_pos_changed = true;
- win_set_inner_size(wp);
+ win_set_inner_size(wp, true);
}
void scroll_to_fraction(win_T *wp, int prev_height)
@@ -6230,7 +6254,7 @@ void scroll_to_fraction(win_T *wp, int prev_height)
if (lnum == 1) {
// first line in buffer is folded
line_size = 1;
- --sline;
+ sline--;
break;
}
lnum--;
@@ -6276,7 +6300,7 @@ void scroll_to_fraction(win_T *wp, int prev_height)
invalidate_botline_win(wp);
}
-void win_set_inner_size(win_T *wp)
+void win_set_inner_size(win_T *wp, bool valid_cursor)
{
int width = wp->w_width_request;
if (width == 0) {
@@ -6290,7 +6314,7 @@ void win_set_inner_size(win_T *wp)
}
if (height != prev_height) {
- if (height > 0) {
+ if (height > 0 && valid_cursor) {
if (wp == curwin) {
// w_wrow needs to be valid. When setting 'laststatus' this may
// call win_new_height() recursively.
@@ -6309,7 +6333,7 @@ void win_set_inner_size(win_T *wp)
// There is no point in adjusting the scroll position when exiting. Some
// values might be invalid.
// Skip scroll_to_fraction() when 'cmdheight' was set to one from zero.
- if (!exiting && !made_cmdheight_nonzero) {
+ if (!exiting && !made_cmdheight_nonzero && valid_cursor) {
scroll_to_fraction(wp, prev_height);
}
redraw_later(wp, NOT_VALID); // SOME_VALID??
@@ -6318,11 +6342,13 @@ void win_set_inner_size(win_T *wp)
if (width != wp->w_width_inner) {
wp->w_width_inner = width;
wp->w_lines_valid = 0;
- changed_line_abv_curs_win(wp);
- invalidate_botline_win(wp);
- if (wp == curwin) {
- update_topline(wp);
- curs_columns(wp, true); // validate w_wrow
+ if (valid_cursor) {
+ changed_line_abv_curs_win(wp);
+ invalidate_botline_win(wp);
+ if (wp == curwin) {
+ update_topline(wp);
+ curs_columns(wp, true); // validate w_wrow
+ }
}
redraw_later(wp, NOT_VALID);
}
@@ -6351,7 +6377,7 @@ static int win_border_width(win_T *wp)
void win_new_width(win_T *wp, int width)
{
wp->w_width = width;
- win_set_inner_size(wp);
+ win_set_inner_size(wp, true);
wp->w_redr_status = true;
wp->w_pos_changed = true;
@@ -6386,6 +6412,19 @@ void command_height(void)
// p_ch was changed in another tab page.
curtab->tp_ch_used = p_ch;
+ // If the space for the command line is already more than 'cmdheight' there
+ // is nothing to do (window size must have decreased).
+ if (p_ch > old_p_ch && cmdline_row <= Rows - p_ch) {
+ return;
+ }
+
+ // If cmdline_row is smaller than what it is supposed to be for 'cmdheight'
+ // then set old_p_ch to what it would be, so that the windows get resized
+ // properly for the new value.
+ if (cmdline_row < Rows - p_ch) {
+ old_p_ch = Rows - cmdline_row;
+ }
+
// Find bottom frame with width of screen.
frp = lastwin_nofloating()->w_frame;
while (frp->fr_width != Columns && frp->fr_parent != NULL) {
@@ -6470,17 +6509,17 @@ char_u *grab_file_name(long count, linenr_T *file_lnum)
int options = FNAME_MESS | FNAME_EXP | FNAME_REL | FNAME_UNESC;
if (VIsual_active) {
size_t len;
- char_u *ptr;
+ char *ptr;
if (get_visual_text(NULL, &ptr, &len) == FAIL) {
return NULL;
}
// Only recognize ":123" here
if (file_lnum != NULL && ptr[len] == ':' && isdigit(ptr[len + 1])) {
- char *p = (char *)ptr + len + 1;
+ char *p = ptr + len + 1;
*file_lnum = (linenr_T)getdigits_long(&p, false, 0);
}
- return find_file_name_in_path(ptr, len, options, count, (char_u *)curbuf->b_ffname);
+ return find_file_name_in_path((char_u *)ptr, len, options, count, (char_u *)curbuf->b_ffname);
}
return file_name_at_cursor(options | FNAME_HYP, count, file_lnum);
}
@@ -6566,7 +6605,7 @@ char_u *file_name_in_line(char_u *line, int col, int options, long count, char_u
if (ptr[len] == '\\' && ptr[len + 1] == ' ') {
// Skip over the "\" in "\ ".
- ++len;
+ len++;
}
len += (size_t)(utfc_ptr2len(ptr + len));
}
@@ -6577,7 +6616,7 @@ char_u *file_name_in_line(char_u *line, int col, int options, long count, char_u
*/
if (len > 2 && vim_strchr(".,:;!", ptr[len - 1]) != NULL
&& ptr[len - 2] != '.') {
- --len;
+ len--;
}
if (file_lnum != NULL) {
@@ -6743,9 +6782,11 @@ static void last_status_rec(frame_T *fr, bool statusline, bool is_stl_global)
/// Add or remove window bar from window "wp".
///
/// @param make_room Whether to resize frames to make room for winbar.
+/// @param valid_cursor Whether the cursor is valid and should be used while
+/// resizing.
///
/// @return Success status.
-int set_winbar_win(win_T *wp, bool make_room)
+int set_winbar_win(win_T *wp, bool make_room, bool valid_cursor)
{
// Require the local value to be set in order to show winbar on a floating window.
int winbar_height = wp->w_floating ? ((*wp->w_p_wbr != NUL) ? 1 : 0)
@@ -6761,7 +6802,7 @@ int set_winbar_win(win_T *wp, bool make_room)
}
}
wp->w_winbar_height = winbar_height;
- win_set_inner_size(wp);
+ win_set_inner_size(wp, valid_cursor);
wp->w_redr_status = wp->w_redr_status || winbar_height;
if (winbar_height == 0) {
@@ -6782,7 +6823,7 @@ int set_winbar_win(win_T *wp, bool make_room)
void set_winbar(bool make_room)
{
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
- if (set_winbar_win(wp, make_room) == FAIL) {
+ if (set_winbar_win(wp, make_room, true) == FAIL) {
break;
}
}
@@ -7100,7 +7141,7 @@ int switch_win(switchwin_T *switchwin, win_T *win, tabpage_T *tp, bool no_displa
// As switch_win() but without blocking autocommands.
int switch_win_noblock(switchwin_T *switchwin, win_T *win, tabpage_T *tp, bool no_display)
{
- memset(switchwin, 0, sizeof(switchwin_T));
+ CLEAR_POINTER(switchwin);
switchwin->sw_curwin = curwin;
if (win == curwin) {
switchwin->sw_same_win = true;
@@ -7233,6 +7274,88 @@ static bool frame_check_width(const frame_T *topfrp, int width)
return true;
}
+/// Simple int comparison function for use with qsort()
+static int int_cmp(const void *a, const void *b)
+{
+ return *(const int *)a - *(const int *)b;
+}
+
+/// Handle setting 'colorcolumn' or 'textwidth' in window "wp".
+///
+/// @return error message, NULL if it's OK.
+char *check_colorcolumn(win_T *wp)
+{
+ char *s;
+ int col;
+ unsigned int count = 0;
+ int color_cols[256];
+ int j = 0;
+
+ if (wp->w_buffer == NULL) {
+ return NULL; // buffer was closed
+ }
+
+ for (s = (char *)wp->w_p_cc; *s != NUL && count < 255;) {
+ if (*s == '-' || *s == '+') {
+ // -N and +N: add to 'textwidth'
+ col = (*s == '-') ? -1 : 1;
+ s++;
+ if (!ascii_isdigit(*s)) {
+ return e_invarg;
+ }
+ col = col * getdigits_int(&s, true, 0);
+ if (wp->w_buffer->b_p_tw == 0) {
+ goto skip; // 'textwidth' not set, skip this item
+ }
+ assert((col >= 0
+ && wp->w_buffer->b_p_tw <= INT_MAX - col
+ && wp->w_buffer->b_p_tw + col >= INT_MIN)
+ || (col < 0
+ && wp->w_buffer->b_p_tw >= INT_MIN - col
+ && wp->w_buffer->b_p_tw + col <= INT_MAX));
+ col += (int)wp->w_buffer->b_p_tw;
+ if (col < 0) {
+ goto skip;
+ }
+ } else if (ascii_isdigit(*s)) {
+ col = getdigits_int(&s, true, 0);
+ } else {
+ return e_invarg;
+ }
+ color_cols[count++] = col - 1; // 1-based to 0-based
+skip:
+ if (*s == NUL) {
+ break;
+ }
+ if (*s != ',') {
+ return e_invarg;
+ }
+ if (*++s == NUL) {
+ return e_invarg; // illegal trailing comma as in "set cc=80,"
+ }
+ }
+
+ xfree(wp->w_p_cc_cols);
+ if (count == 0) {
+ wp->w_p_cc_cols = NULL;
+ } else {
+ wp->w_p_cc_cols = xmalloc(sizeof(int) * (count + 1));
+ // sort the columns for faster usage on screen redraw inside
+ // win_line()
+ qsort(color_cols, count, sizeof(int), int_cmp);
+
+ for (unsigned int i = 0; i < count; i++) {
+ // skip duplicates
+ if (j == 0 || wp->w_p_cc_cols[j - 1] != color_cols[i]) {
+ wp->w_p_cc_cols[j++] = color_cols[i];
+ }
+ }
+ wp->w_p_cc_cols[j] = -1; // end marker
+ }
+
+ return NULL; // no error
+}
+
int win_getid(typval_T *argvars)
{
if (argvars[0].v_type == VAR_UNKNOWN) {