aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/ui_compositor.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/ui_compositor.c')
-rw-r--r--src/nvim/ui_compositor.c122
1 files changed, 83 insertions, 39 deletions
diff --git a/src/nvim/ui_compositor.c b/src/nvim/ui_compositor.c
index 9517b362af..163eadbc95 100644
--- a/src/nvim/ui_compositor.c
+++ b/src/nvim/ui_compositor.c
@@ -19,6 +19,7 @@
#include "nvim/ui.h"
#include "nvim/highlight.h"
#include "nvim/memory.h"
+#include "nvim/message.h"
#include "nvim/popupmnu.h"
#include "nvim/ui_compositor.h"
#include "nvim/ugrid.h"
@@ -46,8 +47,11 @@ static int chk_width = 0, chk_height = 0;
static ScreenGrid *curgrid;
static bool valid_screen = true;
-static bool msg_scroll_mode = false;
-static int msg_first_invalid = 0;
+static int msg_current_row = INT_MAX;
+static bool msg_was_scrolled = false;
+
+static int msg_sep_row = -1;
+static schar_T msg_sep_char = { ' ', NUL };
static int dbghl_normal, dbghl_clear, dbghl_composed, dbghl_recompose;
@@ -63,8 +67,7 @@ void ui_comp_init(void)
compositor->grid_scroll = ui_comp_grid_scroll;
compositor->grid_cursor_goto = ui_comp_grid_cursor_goto;
compositor->raw_line = ui_comp_raw_line;
- compositor->win_scroll_over_start = ui_comp_win_scroll_over_start;
- compositor->win_scroll_over_reset = ui_comp_win_scroll_over_reset;
+ compositor->msg_set_pos = ui_comp_msg_set_pos;
// Be unopinionated: will be attached together with a "real" ui anyway
compositor->width = INT_MAX;
@@ -158,8 +161,19 @@ bool ui_comp_put_grid(ScreenGrid *grid, int row, int col, int height, int width,
}
#endif
+ // TODO(bfredl): this is pretty ad-hoc, add a proper z-order/priority
+ // scheme. For now:
+ // - msg_grid is always on top.
+ // - pum_grid is on top of all windows but not msg_grid. Except for when
+ // wildoptions=pum, and completing the cmdline with scrolled messages,
+ // then the pum has to be drawn over the scrolled messages.
size_t insert_at = kv_size(layers);
- if (kv_A(layers, insert_at-1) == &pum_grid) {
+ bool cmd_completion = (grid == &pum_grid && (State & CMDLINE)
+ && (wop_flags & WOP_PUM));
+ if (kv_A(layers, insert_at-1) == &msg_grid && !cmd_completion) {
+ insert_at--;
+ }
+ if (kv_A(layers, insert_at-1) == &pum_grid && (grid != &msg_grid)) {
insert_at--;
}
if (insert_at > 1 && !on_top) {
@@ -280,10 +294,10 @@ static void ui_comp_grid_cursor_goto(UI *ui, Integer grid_handle,
ScreenGrid *ui_comp_mouse_focus(int row, int col)
{
- // TODO(bfredl): click "through" unfocusable grids?
for (ssize_t i = (ssize_t)kv_size(layers)-1; i > 0; i--) {
ScreenGrid *grid = kv_A(layers, i);
- if (row >= grid->comp_row && row < grid->comp_row+grid->Rows
+ if (grid->focusable
+ && row >= grid->comp_row && row < grid->comp_row+grid->Rows
&& col >= grid->comp_col && col < grid->comp_col+grid->Columns) {
return grid;
}
@@ -337,10 +351,28 @@ static void compose_line(Integer row, Integer startcol, Integer endcol,
assert(until > col);
assert(until <= default_grid.Columns);
size_t n = (size_t)(until-col);
- size_t off = grid->line_offset[row-grid->comp_row]
- + (size_t)(col-grid->comp_col);
- memcpy(linebuf+(col-startcol), grid->chars+off, n * sizeof(*linebuf));
- memcpy(attrbuf+(col-startcol), grid->attrs+off, n * sizeof(*attrbuf));
+
+ if (row == msg_sep_row && grid->comp_index <= msg_grid.comp_index) {
+ grid = &msg_grid;
+ sattr_T msg_sep_attr = (sattr_T)HL_ATTR(HLF_MSGSEP);
+ for (int i = col; i < until; i++) {
+ memcpy(linebuf[i-startcol], msg_sep_char, sizeof(*linebuf));
+ attrbuf[i-startcol] = msg_sep_attr;
+ }
+ } else {
+ size_t off = grid->line_offset[row-grid->comp_row]
+ + (size_t)(col-grid->comp_col);
+ memcpy(linebuf+(col-startcol), grid->chars+off, n * sizeof(*linebuf));
+ memcpy(attrbuf+(col-startcol), grid->attrs+off, n * sizeof(*attrbuf));
+ if (grid->comp_col+grid->Columns > until
+ && grid->chars[off+n][0] == NUL) {
+ linebuf[until-1-startcol][0] = ' ';
+ linebuf[until-1-startcol][1] = '\0';
+ if (col == startcol && n == 1) {
+ skipstart = 0;
+ }
+ }
+ }
// 'pumblend' and 'winblend'
if (grid->blending) {
@@ -375,14 +407,6 @@ static void compose_line(Integer row, Integer startcol, Integer endcol,
} else if (n > 1 && linebuf[col-startcol+1][0] == NUL) {
skipstart = 0;
}
- if (grid->comp_col+grid->Columns > until
- && grid->chars[off+n][0] == NUL) {
- linebuf[until-1-startcol][0] = ' ';
- linebuf[until-1-startcol][1] = '\0';
- if (col == startcol && n == 1) {
- skipstart = 0;
- }
- }
col = until;
}
@@ -500,9 +524,12 @@ static void ui_comp_raw_line(UI *ui, Integer grid, Integer row,
endcol = MIN(endcol, clearcol);
}
- if (flags & kLineFlagInvalid
- || kv_size(layers) > curgrid->comp_index+1
- || curgrid->blending) {
+ bool above_msg = (kv_A(layers, kv_size(layers)-1) == &msg_grid
+ && row < msg_current_row-(msg_was_scrolled?1:0));
+ bool covered = kv_size(layers)-(above_msg?1:0) > curgrid->comp_index+1;
+ // TODO(bfredl): eventually should just fix compose_line to respect clearing
+ // and optimize it for uncovered lines.
+ if (flags & kLineFlagInvalid || covered || curgrid->blending) {
compose_debug(row, row+1, startcol, clearcol, dbghl_composed, true);
compose_line(row, startcol, clearcol, flags);
} else {
@@ -519,27 +546,44 @@ static void ui_comp_raw_line(UI *ui, Integer grid, Integer row,
void ui_comp_set_screen_valid(bool valid)
{
valid_screen = valid;
+ if (!valid) {
+ msg_sep_row = -1;
+ }
}
-// TODO(bfredl): These events are somewhat of a hack. multiline messages
-// should later on be a separate grid, then this would just be ordinary
-// ui_comp_put_grid and ui_comp_remove_grid calls.
-static void ui_comp_win_scroll_over_start(UI *ui)
+static void ui_comp_msg_set_pos(UI *ui, Integer grid, Integer row,
+ Boolean scrolled, String sep_char)
{
- msg_scroll_mode = true;
- msg_first_invalid = ui->height;
-}
+ msg_grid.comp_row = (int)row;
+ if (scrolled && row > 0) {
+ msg_sep_row = (int)row-1;
+ if (sep_char.data) {
+ STRLCPY(msg_sep_char, sep_char.data, sizeof(msg_sep_char));
+ }
+ } else {
+ msg_sep_row = -1;
+ }
-static void ui_comp_win_scroll_over_reset(UI *ui)
-{
- msg_scroll_mode = false;
- for (size_t i = 1; i < kv_size(layers); i++) {
- ScreenGrid *grid = kv_A(layers, i);
- if (grid->comp_row+grid->Rows > msg_first_invalid) {
- compose_area(msg_first_invalid, grid->comp_row+grid->Rows,
- grid->comp_col, grid->comp_col+grid->Columns);
+ if (row > msg_current_row && ui_comp_should_draw()) {
+ compose_area(MAX(msg_current_row-1, 0), row, 0, default_grid.Columns);
+ } else if (row < msg_current_row && ui_comp_should_draw()
+ && msg_current_row < Rows) {
+ int delta = msg_current_row - (int)row;
+ if (msg_grid.blending) {
+ int first_row = MAX((int)row-(scrolled?1:0), 0);
+ compose_area(first_row, Rows-delta, 0, Columns);
+ } else {
+ // scroll separator togheter with message text
+ int first_row = MAX((int)row-(msg_was_scrolled?1:0), 0);
+ ui_composed_call_grid_scroll(1, first_row, Rows, 0, Columns, delta, 0);
+ if (scrolled && !msg_was_scrolled && row > 0) {
+ compose_area(row-1, row, 0, Columns);
+ }
}
}
+
+ msg_current_row = (int)row;
+ msg_was_scrolled = scrolled;
}
static void ui_comp_grid_scroll(UI *ui, Integer grid, Integer top,
@@ -554,7 +598,8 @@ static void ui_comp_grid_scroll(UI *ui, Integer grid, Integer top,
left += curgrid->comp_col;
right += curgrid->comp_col;
bool covered = kv_size(layers) > curgrid->comp_index+1 || curgrid->blending;
- if (!msg_scroll_mode && covered) {
+
+ if (covered) {
// TODO(bfredl):
// 1. check if rectangles actually overlap
// 2. calulate subareas that can scroll.
@@ -565,7 +610,6 @@ static void ui_comp_grid_scroll(UI *ui, Integer grid, Integer top,
}
compose_area(top, bot, left, right);
} else {
- msg_first_invalid = MIN(msg_first_invalid, (int)top);
ui_composed_call_grid_scroll(1, top, bot, left, right, rows, cols);
if (rdb_flags & RDB_COMPOSITOR) {
debug_delay(2);