mirror of
				https://github.com/neovim/neovim.git
				synced 2025-10-26 12:27:24 +00:00 
			
		
		
		
	fix(float): make screen*() functions respect floating windows
				
					
				
			Resolves #19013.
This commit is contained in:
		| @@ -49,6 +49,7 @@ | ||||
| #include "nvim/sign.h" | ||||
| #include "nvim/syntax.h" | ||||
| #include "nvim/ui.h" | ||||
| #include "nvim/ui_compositor.h" | ||||
| #include "nvim/undo.h" | ||||
| #include "nvim/version.h" | ||||
| #include "nvim/window.h" | ||||
| @@ -6849,19 +6850,19 @@ void return_register(int regname, typval_T *rettv) | ||||
|   rettv->vval.v_string = xstrdup(buf); | ||||
| } | ||||
|  | ||||
| void screenchar_adjust_grid(ScreenGrid **grid, int *row, int *col) | ||||
| void screenchar_adjust(ScreenGrid **grid, int *row, int *col) | ||||
| { | ||||
|   // TODO(bfredl): this is a hack for legacy tests which use screenchar() | ||||
|   // to check printed messages on the screen (but not floats etc | ||||
|   // as these are not legacy features). If the compositor is refactored to | ||||
|   // have its own buffer, this should just read from it instead. | ||||
|   msg_scroll_flush(); | ||||
|   if (msg_grid.chars && msg_grid.comp_index > 0 && *row >= msg_grid.comp_row | ||||
|       && *row < (msg_grid.rows + msg_grid.comp_row) | ||||
|       && *col < msg_grid.cols) { | ||||
|     *grid = &msg_grid; | ||||
|     *row -= msg_grid.comp_row; | ||||
|   } | ||||
|  | ||||
|   *grid = ui_comp_get_grid_at_coord(*row, *col); | ||||
|  | ||||
|   // Make `row` and `col` relative to the grid | ||||
|   *row -= (*grid)->comp_row; | ||||
|   *col -= (*grid)->comp_col; | ||||
| } | ||||
|  | ||||
| /// Set line or list of lines in buffer "buf". | ||||
|   | ||||
| @@ -8035,14 +8035,15 @@ static void f_screenattr(typval_T *argvars, typval_T *rettv, FunPtr fptr) | ||||
| { | ||||
|   int c; | ||||
|  | ||||
|   ScreenGrid *grid; | ||||
|   int row = (int)tv_get_number_chk(&argvars[0], NULL) - 1; | ||||
|   int col = (int)tv_get_number_chk(&argvars[1], NULL) - 1; | ||||
|   if (row < 0 || row >= default_grid.rows | ||||
|       || col < 0 || col >= default_grid.cols) { | ||||
|  | ||||
|   screenchar_adjust(&grid, &row, &col); | ||||
|  | ||||
|   if (row < 0 || row >= grid->rows || col < 0 || col >= grid->cols) { | ||||
|     c = -1; | ||||
|   } else { | ||||
|     ScreenGrid *grid = &default_grid; | ||||
|     screenchar_adjust_grid(&grid, &row, &col); | ||||
|     c = grid->attrs[grid->line_offset[row] + col]; | ||||
|   } | ||||
|   rettv->vval.v_number = c; | ||||
| @@ -8053,14 +8054,15 @@ static void f_screenchar(typval_T *argvars, typval_T *rettv, FunPtr fptr) | ||||
| { | ||||
|   int c; | ||||
|  | ||||
|   ScreenGrid *grid; | ||||
|   int row = tv_get_number_chk(&argvars[0], NULL) - 1; | ||||
|   int col = tv_get_number_chk(&argvars[1], NULL) - 1; | ||||
|   if (row < 0 || row >= default_grid.rows | ||||
|       || col < 0 || col >= default_grid.cols) { | ||||
|  | ||||
|   screenchar_adjust(&grid, &row, &col); | ||||
|  | ||||
|   if (row < 0 || row >= grid->rows || col < 0 || col >= grid->cols) { | ||||
|     c = -1; | ||||
|   } else { | ||||
|     ScreenGrid *grid = &default_grid; | ||||
|     screenchar_adjust_grid(&grid, &row, &col); | ||||
|     c = utf_ptr2char((char *)grid->chars[grid->line_offset[row] + col]); | ||||
|   } | ||||
|   rettv->vval.v_number = c; | ||||
| @@ -8069,15 +8071,16 @@ static void f_screenchar(typval_T *argvars, typval_T *rettv, FunPtr fptr) | ||||
| /// "screenchars()" function | ||||
| static void f_screenchars(typval_T *argvars, typval_T *rettv, FunPtr fptr) | ||||
| { | ||||
|   ScreenGrid *grid; | ||||
|   int row = tv_get_number_chk(&argvars[0], NULL) - 1; | ||||
|   int col = tv_get_number_chk(&argvars[1], NULL) - 1; | ||||
|   if (row < 0 || row >= default_grid.rows | ||||
|       || col < 0 || col >= default_grid.cols) { | ||||
|  | ||||
|   screenchar_adjust(&grid, &row, &col); | ||||
|  | ||||
|   if (row < 0 || row >= grid->rows || col < 0 || col >= grid->cols) { | ||||
|     tv_list_alloc_ret(rettv, 0); | ||||
|     return; | ||||
|   } | ||||
|   ScreenGrid *grid = &default_grid; | ||||
|   screenchar_adjust_grid(&grid, &row, &col); | ||||
|   int pcc[MAX_MCO]; | ||||
|   int c = utfc_ptr2char(grid->chars[grid->line_offset[row] + col], pcc); | ||||
|   int composing_len = 0; | ||||
| @@ -8136,14 +8139,17 @@ static void f_screenstring(typval_T *argvars, typval_T *rettv, FunPtr fptr) | ||||
| { | ||||
|   rettv->vval.v_string = NULL; | ||||
|   rettv->v_type = VAR_STRING; | ||||
|  | ||||
|   ScreenGrid *grid; | ||||
|   int row = tv_get_number_chk(&argvars[0], NULL) - 1; | ||||
|   int col = tv_get_number_chk(&argvars[1], NULL) - 1; | ||||
|   if (row < 0 || row >= default_grid.rows | ||||
|       || col < 0 || col >= default_grid.cols) { | ||||
|  | ||||
|   screenchar_adjust(&grid, &row, &col); | ||||
|  | ||||
|   if (row < 0 || row >= grid->rows || col < 0 || col >= grid->cols) { | ||||
|     return; | ||||
|   } | ||||
|   ScreenGrid *grid = &default_grid; | ||||
|   screenchar_adjust_grid(&grid, &row, &col); | ||||
|  | ||||
|   rettv->vval.v_string = (char *)vim_strsave(grid->chars[grid->line_offset[row] + col]); | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -300,6 +300,19 @@ ScreenGrid *ui_comp_mouse_focus(int row, int col) | ||||
|   return NULL; | ||||
| } | ||||
|  | ||||
| /// Compute which grid is on top at supplied screen coordinates | ||||
| ScreenGrid *ui_comp_get_grid_at_coord(int row, int col) | ||||
| { | ||||
|   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 | ||||
|         && col >= grid->comp_col && col < grid->comp_col + grid->cols) { | ||||
|       return grid; | ||||
|     } | ||||
|   } | ||||
|   return &default_grid; | ||||
| } | ||||
|  | ||||
| /// Baseline implementation. This is always correct, but we can sometimes | ||||
| /// do something more efficient (where efficiency means smaller deltas to | ||||
| /// the downstream UI.) | ||||
|   | ||||
							
								
								
									
										69
									
								
								test/functional/vimscript/screenchar_spec.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								test/functional/vimscript/screenchar_spec.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,69 @@ | ||||
| local helpers = require('test.functional.helpers')(after_each) | ||||
| local clear, eq, neq = helpers.clear, helpers.eq, helpers.neq | ||||
| local command, meths, funcs = helpers.command, helpers.meths, helpers.funcs | ||||
| local tbl_deep_extend = helpers.tbl_deep_extend | ||||
|  | ||||
| -- Set up two overlapping floating windows | ||||
| local setup_floating_windows = function() | ||||
|   local base_opts = { | ||||
|     relative = 'editor', | ||||
|     height = 1, | ||||
|     width = 2, | ||||
|     anchor = 'NW', | ||||
|     style = 'minimal', | ||||
|     border = 'none', | ||||
|   } | ||||
|  | ||||
|   local bufnr_1 = meths.create_buf(false, true) | ||||
|   meths.buf_set_lines(bufnr_1, 0, -1, true, { 'aa' }) | ||||
|   local opts_1 = tbl_deep_extend('force', { row = 0, col = 0, zindex = 11 }, base_opts) | ||||
|   meths.open_win(bufnr_1, false, opts_1) | ||||
|  | ||||
|   local bufnr_2 = meths.create_buf(false, true) | ||||
|   meths.buf_set_lines(bufnr_2, 0, -1, true, { 'bb' }) | ||||
|   local opts_2 = tbl_deep_extend('force', { row = 0, col = 1, zindex = 10 }, base_opts) | ||||
|   meths.open_win(bufnr_2, false, opts_2) | ||||
|  | ||||
|   command('redraw') | ||||
| end | ||||
|  | ||||
| describe('screenchar() and family respect floating windows', function() | ||||
|   before_each(function() | ||||
|     clear() | ||||
|     -- These commands result into visible text `aabc`. | ||||
|     -- `aab` - from floating windows, `c` - from text in regular window. | ||||
|     meths.buf_set_lines(0, 0, -1, true, { 'cccc' }) | ||||
|     setup_floating_windows() | ||||
|   end) | ||||
|  | ||||
|   it('screenattr()', function() | ||||
|     local attr_1 = funcs.screenattr(1, 1) | ||||
|     local attr_2 = funcs.screenattr(1, 2) | ||||
|     local attr_3 = funcs.screenattr(1, 3) | ||||
|     local attr_4 = funcs.screenattr(1, 4) | ||||
|     eq(attr_1, attr_2) | ||||
|     eq(attr_1, attr_3) | ||||
|     neq(attr_1, attr_4) | ||||
|   end) | ||||
|  | ||||
|   it('screenchar()', function() | ||||
|     eq(97, funcs.screenchar(1, 1)) | ||||
|     eq(97, funcs.screenchar(1, 2)) | ||||
|     eq(98, funcs.screenchar(1, 3)) | ||||
|     eq(99, funcs.screenchar(1, 4)) | ||||
|   end) | ||||
|  | ||||
|   it('screenchars()', function() | ||||
|     eq({ 97 }, funcs.screenchars(1, 1)) | ||||
|     eq({ 97 }, funcs.screenchars(1, 2)) | ||||
|     eq({ 98 }, funcs.screenchars(1, 3)) | ||||
|     eq({ 99 }, funcs.screenchars(1, 4)) | ||||
|   end) | ||||
|  | ||||
|   it('screenstring()', function() | ||||
|     eq('a', funcs.screenstring(1, 1)) | ||||
|     eq('a', funcs.screenstring(1, 2)) | ||||
|     eq('b', funcs.screenstring(1, 3)) | ||||
|     eq('c', funcs.screenstring(1, 4)) | ||||
|   end) | ||||
| end) | ||||
		Reference in New Issue
	
	Block a user
	 Evgeni Chasnovski
					Evgeni Chasnovski