vim-patch:8.1.1071: cannot get composing characters from the screen

Problem:    Cannot get composing characters from the screen.
Solution:   Add screenchars() and screenstring(). (partly by Ozaki Kiichi,
            closes vim/vim#4059)
2912abb3a2
This commit is contained in:
zeertzjq 2021-09-19 13:13:44 +08:00
parent 924e8e4f2d
commit 963474321b
6 changed files with 123 additions and 17 deletions

View File

@ -2596,9 +2596,11 @@ rpcrequest({channel}, {method}[, {args}...])
Sends an |RPC| request to {channel}
screenattr({row}, {col}) Number attribute at screen position
screenchar({row}, {col}) Number character at screen position
screenchars({row}, {col}) List List of characters at screen position
screencol() Number current cursor column
screenpos({winid}, {lnum}, {col}) Dict screen row and col of a text character
screenrow() Number current cursor row
screenstring({row}, {col}) String characters at screen position
search({pattern} [, {flags} [, {stopline} [, {timeout}]]])
Number search for {pattern}
searchcount([{options}]) Dict Get or update the last search count
@ -7669,6 +7671,13 @@ screenchar({row}, {col}) *screenchar()*
This is mainly to be used for testing.
Returns -1 when row or col is out of range.
screenchars({row}, {col}) *screenchars()*
The result is a List of Numbers. The first number is the same
as what |screenchar()| returns. Further numbers are
composing characters on top of the base character.
This is mainly to be used for testing.
Returns an empty List when row or col is out of range.
screencol() *screencol()*
The result is a Number, which is the current screen column of
the cursor. The leftmost column has number 1.
@ -7712,6 +7721,14 @@ screenrow() *screenrow()*
Note: Same restrictions as with |screencol()|.
screenstring({row}, {col}) *screenstring()*
The result is a String that contains the base character and
any composing characters at position [row, col] on the screen.
This is like |screenchars()| but returning a String with the
characters.
This is mainly to be used for testing.
Returns an empty String when row or col is out of range.
search({pattern} [, {flags} [, {stopline} [, {timeout}]]]) *search()*
Search for regexp pattern {pattern}. The search starts at the
cursor position (you can use |cursor()| to set it).

View File

@ -744,6 +744,8 @@ Cursor and mark position: *cursor-functions* *mark-functions*
diff_filler() get the number of filler lines above a line
screenattr() get attribute at a screen line/row
screenchar() get character code at a screen line/row
screenchars() get character codes at a screen line/row
screenstring() get string of characters at a screen line/row
Working with text in the current buffer: *text-functions*
getline() get a line or list of lines from the buffer

View File

@ -290,9 +290,11 @@ return {
rubyeval={args=1},
screenattr={args=2},
screenchar={args=2},
screenchars={args=2},
screencol={},
screenpos={args=3},
screenrow={},
screenstring={args=2},
search={args={1, 4}},
searchcount={args={0,1}},
searchdecl={args={1, 3}},

View File

@ -8108,9 +8108,7 @@ static void f_rpcstop(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
}
/*
* "screenattr()" function
*/
// "screenattr()" function
static void f_screenattr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
int c;
@ -8128,9 +8126,7 @@ static void f_screenattr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
rettv->vval.v_number = c;
}
/*
* "screenchar()" function
*/
// "screenchar()" function
static void f_screenchar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
int c;
@ -8148,11 +8144,34 @@ static void f_screenchar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
rettv->vval.v_number = c;
}
/*
* "screencol()" function
*
* First column is 1 to be consistent with virtcol().
*/
// "screenchars()" function
static void f_screenchars(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
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.Columns) {
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;
while (pcc[composing_len] != 0) {
composing_len++;
}
tv_list_alloc_ret(rettv, composing_len + 1);
tv_list_append_number(rettv->vval.v_list, c);
for (int i = 0; i < composing_len; i++) {
tv_list_append_number(rettv->vval.v_list, pcc[i]);
}
}
// "screencol()" function
//
// First column is 1 to be consistent with virtcol().
static void f_screencol(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
rettv->vval.v_number = ui_current_col() + 1;
@ -8184,17 +8203,29 @@ static void f_screenpos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
tv_dict_add_nr(dict, S_LEN("endcol"), ecol);
}
/*
* "screenrow()" function
*/
// "screenrow()" function
static void f_screenrow(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
rettv->vval.v_number = ui_current_row() + 1;
}
/*
* "search()" function
*/
// "screenstring()" function
static void f_screenstring(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
rettv->vval.v_string = NULL;
rettv->v_type = VAR_STRING;
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.Columns) {
return;
}
ScreenGrid *grid = &default_grid;
screenchar_adjust_grid(&grid, &row, &col);
rettv->vval.v_string = vim_strsave(grid->chars[grid->line_offset[row] + col]);
}
// "search()" function
static void f_search(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
int flags = 0;

View File

@ -1,5 +1,6 @@
" Tests for Unicode manipulations
source view_util.vim
" Visual block Insert adjusts for multi-byte char
func Test_visual_block_insert()
@ -61,6 +62,40 @@ func Test_getvcol()
call assert_equal(2, virtcol("']"))
endfunc
func Test_screenchar_utf8()
new
" 1-cell, with composing characters
call setline(1, ["ABC\u0308"])
redraw
call assert_equal([0x0041], screenchars(1, 1))
call assert_equal([0x0042], screenchars(1, 2))
call assert_equal([0x0043, 0x0308], screenchars(1, 3))
call assert_equal("A", screenstring(1, 1))
call assert_equal("B", screenstring(1, 2))
call assert_equal("C\u0308", screenstring(1, 3))
" 2-cells, with composing characters
let text = "\u3042\u3044\u3046\u3099"
call setline(1, text)
redraw
call assert_equal([0x3042], screenchars(1, 1))
call assert_equal([0], screenchars(1, 2))
call assert_equal([0x3044], screenchars(1, 3))
call assert_equal([0], screenchars(1, 4))
call assert_equal([0x3046, 0x3099], screenchars(1, 5))
call assert_equal("\u3042", screenstring(1, 1))
call assert_equal("", screenstring(1, 2))
call assert_equal("\u3044", screenstring(1, 3))
call assert_equal("", screenstring(1, 4))
call assert_equal("\u3046\u3099", screenstring(1, 5))
call assert_equal([text . ' '], ScreenLinesUtf8(1, 8))
bwipe!
endfunc
func Test_list2str_str2list_utf8()
" One Unicode codepoint
let s = "\u3042\u3044"

View File

@ -34,6 +34,25 @@ function! ScreenLines(lnum, width) abort
return lines
endfunction
" Get text on the screen, including composing characters.
" ScreenLines(lnum, width) or
" ScreenLines([start, end], width)
function! ScreenLinesUtf8(lnum, width) abort
redraw!
if type(a:lnum) == v:t_list
let start = a:lnum[0]
let end = a:lnum[1]
else
let start = a:lnum
let end = a:lnum
endif
let lines = []
for l in range(start, end)
let lines += [join(map(range(1, a:width), 'screenstring(l, v:val)'), '')]
endfor
return lines
endfunction
function! ScreenAttrs(lnum, width) abort
redraw!
if type(a:lnum) == v:t_list