aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/nvim/api/ui.c9
-rw-r--r--src/nvim/log.c27
-rw-r--r--src/nvim/os/time.c4
-rw-r--r--src/nvim/screen.c8
-rw-r--r--src/nvim/tui/tui.c13
-rw-r--r--src/nvim/ugrid.c2
-rw-r--r--test/functional/ui/screen.lua38
-rw-r--r--test/functional/ui/screen_basic_spec.lua95
8 files changed, 165 insertions, 31 deletions
diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c
index 63c2c4a1b9..d0db43c588 100644
--- a/src/nvim/api/ui.c
+++ b/src/nvim/api/ui.c
@@ -302,6 +302,15 @@ static void remote_ui_grid_scroll(UI *ui, Integer grid, Integer top,
args = (Array)ARRAY_DICT_INIT;
ADD(args, INTEGER_OBJ(rows));
push_call(ui, "scroll", args);
+
+ // some clients have "clear" being affected by scroll region,
+ // so reset it.
+ args = (Array)ARRAY_DICT_INIT;
+ ADD(args, INTEGER_OBJ(0));
+ ADD(args, INTEGER_OBJ(ui->height-1));
+ ADD(args, INTEGER_OBJ(0));
+ ADD(args, INTEGER_OBJ(ui->width-1));
+ push_call(ui, "set_scroll_region", args);
}
}
diff --git a/src/nvim/log.c b/src/nvim/log.c
index 7bfe5c4089..e485d4c338 100644
--- a/src/nvim/log.c
+++ b/src/nvim/log.c
@@ -7,6 +7,9 @@
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
+#if !defined(WIN32)
+# include <sys/time.h> // for gettimeofday()
+#endif
#include <uv.h>
#include "nvim/log.h"
@@ -260,25 +263,33 @@ static bool v_do_log_to_file(FILE *log_file, int log_level,
};
assert(log_level >= DEBUG_LOG_LEVEL && log_level <= ERROR_LOG_LEVEL);
- // format current timestamp in local time
+ // Format the timestamp.
struct tm local_time;
- if (os_get_localtime(&local_time) == NULL) {
+ if (os_localtime(&local_time) == NULL) {
return false;
}
char date_time[20];
- if (strftime(date_time, sizeof(date_time), "%Y/%m/%d %H:%M:%S",
+ if (strftime(date_time, sizeof(date_time), "%Y-%m-%dT%H:%M:%S",
&local_time) == 0) {
return false;
}
- // print the log message prefixed by the current timestamp and pid
+ int millis = 0;
+#if !defined(WIN32)
+ struct timeval curtime;
+ if (gettimeofday(&curtime, NULL) == 0) {
+ millis = (int)curtime.tv_usec / 1000;
+ }
+#endif
+
+ // Print the log message.
int64_t pid = os_get_pid();
int rv = (line_num == -1 || func_name == NULL)
- ? fprintf(log_file, "%s %s %" PRId64 " %s", date_time,
- log_levels[log_level], pid,
+ ? fprintf(log_file, "%s %s.%03d %-5" PRId64 " %s",
+ log_levels[log_level], date_time, millis, pid,
(context == NULL ? "?:" : context))
- : fprintf(log_file, "%s %s %" PRId64 " %s%s:%d: ", date_time,
- log_levels[log_level], pid,
+ : fprintf(log_file, "%s %s.%03d %-5" PRId64 " %s%s:%d: ",
+ log_levels[log_level], date_time, millis, pid,
(context == NULL ? "" : context),
func_name, line_num);
if (rv < 0) {
diff --git a/src/nvim/os/time.c b/src/nvim/os/time.c
index 290d421acc..31ef1a0cd6 100644
--- a/src/nvim/os/time.c
+++ b/src/nvim/os/time.c
@@ -114,12 +114,12 @@ struct tm *os_localtime_r(const time_t *restrict clock,
#endif
}
-/// Obtains the current Unix timestamp and adjusts it to local time.
+/// Gets the current Unix timestamp and adjusts it to local time.
///
/// @param result Pointer to a 'struct tm' where the result should be placed
/// @return A pointer to a 'struct tm' in the current time zone (the 'result'
/// argument) or NULL in case of error
-struct tm *os_get_localtime(struct tm *result) FUNC_ATTR_NONNULL_ALL
+struct tm *os_localtime(struct tm *result) FUNC_ATTR_NONNULL_ALL
{
time_t rawtime = time(NULL);
return os_localtime_r(&rawtime, result);
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index 65a3c17286..e8dbc11710 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -283,8 +283,11 @@ void update_screen(int type)
if (msg_scrolled) {
clear_cmdline = true;
if (dy_flags & DY_MSGSEP) {
+ int valid = MAX(Rows - msg_scrollsize(), 0);
+ if (valid == 0) {
+ redraw_tabline = true;
+ }
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
- int valid = Rows - msg_scrollsize();
if (wp->w_winrow + wp->w_height > valid) {
wp->w_redr_type = NOT_VALID;
wp->w_lines_valid = 0;
@@ -292,9 +295,6 @@ void update_screen(int type)
if (wp->w_winrow + wp->w_height + wp->w_status_height > valid) {
wp->w_redr_status = true;
}
- if (valid == 0) {
- redraw_tabline = true;
- }
}
} else if (msg_scrolled > Rows - 5) { // clearing is faster
type = CLEAR;
diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c
index 56c47ed6cc..508d25cd3b 100644
--- a/src/nvim/tui/tui.c
+++ b/src/nvim/tui/tui.c
@@ -802,7 +802,16 @@ static void reset_scroll_region(UI *ui)
static void tui_grid_resize(UI *ui, Integer g, Integer width, Integer height)
{
TUIData *data = ui->data;
- ugrid_resize(&data->grid, (int)width, (int)height);
+ UGrid *grid = &data->grid;
+ ugrid_resize(grid, (int)width, (int)height);
+
+ // resize might not always be followed by a clear before flush
+ // so clip the invalid region
+ for (size_t i = 0; i < kv_size(data->invalid_regions); i++) {
+ Rect *r = &kv_A(data->invalid_regions, i);
+ r->bot = MIN(r->bot, grid->height-1);
+ r->right = MIN(r->right, grid->width-1);
+ }
if (!got_winch) { // Try to resize the terminal window.
UNIBI_SET_NUM_VAR(data->params[0], (int)height);
@@ -823,7 +832,7 @@ static void tui_grid_clear(UI *ui, Integer g)
UGrid *grid = &data->grid;
ugrid_clear(grid);
kv_size(data->invalid_regions) = 0;
- clear_region(ui, grid->top, grid->bot, grid->left, grid->right,
+ clear_region(ui, 0, grid->height-1, 0, grid->width-1,
data->clear_attrs);
}
diff --git a/src/nvim/ugrid.c b/src/nvim/ugrid.c
index 48f3cff2d7..36936970f8 100644
--- a/src/nvim/ugrid.c
+++ b/src/nvim/ugrid.c
@@ -44,7 +44,7 @@ void ugrid_resize(UGrid *grid, int width, int height)
void ugrid_clear(UGrid *grid)
{
- clear_region(grid, grid->top, grid->bot, grid->left, grid->right,
+ clear_region(grid, 0, grid->height-1, 0, grid->width-1,
HLATTRS_INIT);
}
diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua
index d71d8cf3a8..c40b2210ff 100644
--- a/test/functional/ui/screen.lua
+++ b/test/functional/ui/screen.lua
@@ -73,6 +73,7 @@
local helpers = require('test.functional.helpers')(nil)
local request, run, uimeths = helpers.request, helpers.run, helpers.uimeths
+local eq = helpers.eq
local dedent = helpers.dedent
local Screen = {}
@@ -389,12 +390,21 @@ function Screen:_handle_mode_info_set(cursor_style_enabled, mode_info)
end
function Screen:_handle_clear()
+ -- the first implemented UI protocol clients (python-gui and builitin TUI)
+ -- allowed the cleared region to be restricted by setting the scroll region.
+ -- this was never used by nvim tough, and not documented and implemented by
+ -- newer clients, to check we remain compatible with both kind of clients,
+ -- ensure the scroll region is in a reset state.
+ local expected_region = {
+ top = 1, bot = self._height, left = 1, right = self._width
+ }
+ eq(expected_region, self._scroll_region)
self:_clear_block(1, self._height, 1, self._width)
end
function Screen:_handle_grid_clear(grid)
assert(grid == 1)
- self:_handle_clear()
+ self:_clear_block(1, self._height, 1, self._width)
end
function Screen:_handle_eol_clear()
@@ -446,22 +456,30 @@ function Screen:_handle_scroll(count)
local bot = self._scroll_region.bot
local left = self._scroll_region.left
local right = self._scroll_region.right
+ self:_handle_grid_scroll(1, top-1, bot, left-1, right, count, 0)
+end
+
+function Screen:_handle_grid_scroll(grid, top, bot, left, right, rows, cols)
+ top = top+1
+ left = left+1
+ assert(grid == 1)
+ assert(cols == 0)
local start, stop, step
- if count > 0 then
+ if rows > 0 then
start = top
- stop = bot - count
+ stop = bot - rows
step = 1
else
start = bot
- stop = top - count
+ stop = top - rows
step = -1
end
-- shift scroll region
for i = start, stop, step do
local target = self._rows[i]
- local source = self._rows[i + count]
+ local source = self._rows[i + rows]
for j = left, right do
target[j].text = source[j].text
target[j].attrs = source[j].attrs
@@ -470,19 +488,11 @@ function Screen:_handle_scroll(count)
end
-- clear invalid rows
- for i = stop + step, stop + count, step do
+ for i = stop + step, stop + rows, step do
self:_clear_row_section(i, left, right)
end
end
-function Screen:_handle_grid_scroll(grid, top, bot, left, right, rows, cols)
- assert(grid == 1)
- assert(cols == 0)
- -- TODO: if we truly believe we should translate the other way
- self:_handle_set_scroll_region(top,bot-1,left,right-1)
- self:_handle_scroll(rows)
-end
-
function Screen:_handle_hl_attr_define(id, rgb_attrs, cterm_attrs, info)
self._attr_table[id] = {rgb_attrs, cterm_attrs}
self._hl_info[id] = info
diff --git a/test/functional/ui/screen_basic_spec.lua b/test/functional/ui/screen_basic_spec.lua
index 75a2d4978d..957d8c0915 100644
--- a/test/functional/ui/screen_basic_spec.lua
+++ b/test/functional/ui/screen_basic_spec.lua
@@ -354,6 +354,101 @@ local function screen_tests(newgrid)
{0:~ }|
|
]])
+
+ feed(':echo "'..string.rep('x\\n', 12)..'"<cr>')
+ screen:expect([[
+ x |
+ x |
+ x |
+ x |
+ x |
+ x |
+ x |
+ x |
+ x |
+ x |
+ x |
+ x |
+ |
+ {7:Press ENTER or type command to continue}^ |
+ ]])
+
+ feed('<cr>')
+ screen:expect([[
+ {4: [No Name] }{2: [No Name] }{3: }{4:X}|
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+
+ end)
+
+ it('redraws properly with :tab split right after scroll', function()
+ feed('30Ofoo<esc>gg')
+
+ command('vsplit')
+ screen:expect([[
+ ^foo {3:│}foo |
+ foo {3:│}foo |
+ foo {3:│}foo |
+ foo {3:│}foo |
+ foo {3:│}foo |
+ foo {3:│}foo |
+ foo {3:│}foo |
+ foo {3:│}foo |
+ foo {3:│}foo |
+ foo {3:│}foo |
+ foo {3:│}foo |
+ foo {3:│}foo |
+ {1:[No Name] [+] }{3:[No Name] [+] }|
+ |
+ ]])
+
+ feed('<PageDown>')
+ screen:expect([[
+ ^foo {3:│}foo |
+ foo {3:│}foo |
+ foo {3:│}foo |
+ foo {3:│}foo |
+ foo {3:│}foo |
+ foo {3:│}foo |
+ foo {3:│}foo |
+ foo {3:│}foo |
+ foo {3:│}foo |
+ foo {3:│}foo |
+ foo {3:│}foo |
+ foo {3:│}foo |
+ {1:[No Name] [+] }{3:[No Name] [+] }|
+ |
+ ]])
+
+ command('tab split')
+ screen:expect([[
+ {4: }{5:2}{4:+ [No Name] }{2: + [No Name] }{3: }{4:X}|
+ ^foo |
+ foo |
+ foo |
+ foo |
+ foo |
+ foo |
+ foo |
+ foo |
+ foo |
+ foo |
+ foo |
+ foo |
+ |
+ ]])
end)
end)