1
0
forked from aniani/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 #4059)
This commit is contained in:
Bram Moolenaar
2019-03-29 14:16:42 +01:00
parent e46736b23b
commit 2912abb3a2
6 changed files with 151 additions and 2 deletions

View File

@@ -2525,8 +2525,10 @@ round({expr}) Float round off {expr}
rubyeval({expr}) any evaluate |Ruby| expression
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
screenrow() Number current cursor row
screenstring({row}, {col}) String characters at screen position
search({pattern} [, {flags} [, {stopline} [, {timeout}]]])
Number search for {pattern}
searchdecl({name} [, {global} [, {thisblock}]])
@@ -7510,6 +7512,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.
@@ -7531,6 +7540,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

@@ -723,6 +723,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

@@ -344,8 +344,10 @@ static void f_rubyeval(typval_T *argvars, typval_T *rettv);
#endif
static void f_screenattr(typval_T *argvars, typval_T *rettv);
static void f_screenchar(typval_T *argvars, typval_T *rettv);
static void f_screenchars(typval_T *argvars, typval_T *rettv);
static void f_screencol(typval_T *argvars, typval_T *rettv);
static void f_screenrow(typval_T *argvars, typval_T *rettv);
static void f_screenstring(typval_T *argvars, typval_T *rettv);
static void f_search(typval_T *argvars, typval_T *rettv);
static void f_searchdecl(typval_T *argvars, typval_T *rettv);
static void f_searchpair(typval_T *argvars, typval_T *rettv);
@@ -839,8 +841,10 @@ static struct fst
#endif
{"screenattr", 2, 2, f_screenattr},
{"screenchar", 2, 2, f_screenchar},
{"screenchars", 2, 2, f_screenchars},
{"screencol", 0, 0, f_screencol},
{"screenrow", 0, 0, f_screenrow},
{"screenstring", 2, 2, f_screenstring},
{"search", 1, 4, f_search},
{"searchdecl", 1, 3, f_searchdecl},
{"searchpair", 3, 7, f_searchpair},
@@ -10430,8 +10434,7 @@ f_screenchar(typval_T *argvars, typval_T *rettv)
row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
if (row < 0 || row >= screen_Rows
|| col < 0 || col >= screen_Columns)
if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
c = -1;
else
{
@@ -10444,6 +10447,39 @@ f_screenchar(typval_T *argvars, typval_T *rettv)
rettv->vval.v_number = c;
}
/*
* "screenchars()" function
*/
static void
f_screenchars(typval_T *argvars, typval_T *rettv)
{
int row;
int col;
int off;
int c;
int i;
if (rettv_list_alloc(rettv) == FAIL)
return;
row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
return;
off = LineOffset[row] + col;
if (enc_utf8 && ScreenLinesUC[off] != 0)
c = ScreenLinesUC[off];
else
c = ScreenLines[off];
list_append_number(rettv->vval.v_list, (varnumber_T)c);
if (enc_utf8)
for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
list_append_number(rettv->vval.v_list,
(varnumber_T)ScreenLinesC[i][off]);
}
/*
* "screencol()" function
*
@@ -10464,6 +10500,43 @@ f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
rettv->vval.v_number = screen_screenrow() + 1;
}
/*
* "screenstring()" function
*/
static void
f_screenstring(typval_T *argvars, typval_T *rettv)
{
int row;
int col;
int off;
int c;
int i;
char_u buf[MB_MAXBYTES + 1];
int buflen = 0;
rettv->vval.v_string = NULL;
rettv->v_type = VAR_STRING;
row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
return;
off = LineOffset[row] + col;
if (enc_utf8 && ScreenLinesUC[off] != 0)
c = ScreenLinesUC[off];
else
c = ScreenLines[off];
buflen += mb_char2bytes(c, buf);
if (enc_utf8)
for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
buflen += mb_char2bytes(ScreenLinesC[i][off], buf + buflen);
buf[buflen] = NUL;
rettv->vval.v_string = vim_strsave(buf);
}
/*
* "search()" function
*/

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()
@@ -60,3 +61,37 @@ func Test_getvcol()
call assert_equal(2, virtcol("'["))
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

View File

@@ -5,6 +5,7 @@ if exists('*ScreenLines')
finish
endif
" Get text on the screen, without composing characters.
" ScreenLines(lnum, width) or
" ScreenLines([start, end], width)
function! ScreenLines(lnum, width) abort
@@ -23,6 +24,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

View File

@@ -775,6 +775,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
1071,
/**/
1070,
/**/