mirror of
				https://github.com/neovim/neovim.git
				synced 2025-10-26 12:27:24 +00:00 
			
		
		
		
	vim-patch:9.1.1011: popupmenu internal error with some abbr in completion item (#31988)
Problem:  Popup menu internal error with some abbr in completion item.
Solution: Don't compute attributes when there is no corresponding text.
          Reduce indent in pum_redraw() while at it (zeertzjq).
fixes: vim/vim#16427
closes: vim/vim#16435
3a0cc36c69
			
			
This commit is contained in:
		| @@ -412,7 +412,7 @@ void pum_display(pumitem_T *array, int size, int selected, bool array_changed, i | |||||||
| /// Returns attributes for every cell, or NULL if all attributes are the same. | /// Returns attributes for every cell, or NULL if all attributes are the same. | ||||||
| static int *pum_compute_text_attrs(char *text, hlf_T hlf, int user_hlattr) | static int *pum_compute_text_attrs(char *text, hlf_T hlf, int user_hlattr) | ||||||
| { | { | ||||||
|   if ((hlf != HLF_PSI && hlf != HLF_PNI) |   if (*text == NUL || (hlf != HLF_PSI && hlf != HLF_PNI) | ||||||
|       || (win_hl_attr(curwin, HLF_PMSI) == win_hl_attr(curwin, HLF_PSI) |       || (win_hl_attr(curwin, HLF_PMSI) == win_hl_attr(curwin, HLF_PSI) | ||||||
|           && win_hl_attr(curwin, HLF_PMNI) == win_hl_attr(curwin, HLF_PNI))) { |           && win_hl_attr(curwin, HLF_PMNI) == win_hl_attr(curwin, HLF_PNI))) { | ||||||
|     return NULL; |     return NULL; | ||||||
| @@ -654,24 +654,27 @@ void pum_redraw(void) | |||||||
|             s = p; |             s = p; | ||||||
|           } |           } | ||||||
|           int w = ptr2cells(p); |           int w = ptr2cells(p); | ||||||
|  |           if (*p != NUL && *p != TAB && totwidth + w <= pum_width) { | ||||||
|  |             width += w; | ||||||
|  |             continue; | ||||||
|  |           } | ||||||
|  |  | ||||||
|           if ((*p == NUL) || (*p == TAB) || (totwidth + w > pum_width)) { |  | ||||||
|           // Display the text that fits or comes before a Tab. |           // Display the text that fits or comes before a Tab. | ||||||
|           // First convert it to printable characters. |           // First convert it to printable characters. | ||||||
|             char *st; |  | ||||||
|           char saved = *p; |           char saved = *p; | ||||||
|  |  | ||||||
|           if (saved != NUL) { |           if (saved != NUL) { | ||||||
|             *p = NUL; |             *p = NUL; | ||||||
|           } |           } | ||||||
|             st = transstr(s, true); |           char *st = transstr(s, true); | ||||||
|           if (saved != NUL) { |           if (saved != NUL) { | ||||||
|             *p = saved; |             *p = saved; | ||||||
|           } |           } | ||||||
|  |  | ||||||
|           int *attrs = NULL; |           int *attrs = NULL; | ||||||
|           if (item_type == CPT_ABBR) { |           if (item_type == CPT_ABBR) { | ||||||
|               attrs = pum_compute_text_attrs(st, hlf, pum_array[idx].pum_user_abbr_hlattr); |             attrs = pum_compute_text_attrs(st, hlf, | ||||||
|  |                                            pum_array[idx].pum_user_abbr_hlattr); | ||||||
|           } |           } | ||||||
|  |  | ||||||
|           if (pum_rl) { |           if (pum_rl) { | ||||||
| @@ -686,9 +689,8 @@ void pum_redraw(void) | |||||||
|               } while (cells > pum_width); |               } while (cells > pum_width); | ||||||
|  |  | ||||||
|               if (cells < pum_width) { |               if (cells < pum_width) { | ||||||
|                   // Most left character requires 2-cells but only 1 cell |                 // Most left character requires 2-cells but only 1 cell is available on | ||||||
|                   // is available on screen.  Put a '<' on the left of the |                 // screen.  Put a '<' on the left of the pum item. | ||||||
|                   // pum item |  | ||||||
|                 *(--rt) = '<'; |                 *(--rt) = '<'; | ||||||
|                 cells++; |                 cells++; | ||||||
|               } |               } | ||||||
| @@ -731,12 +733,8 @@ void pum_redraw(void) | |||||||
|             grid_col += 2; |             grid_col += 2; | ||||||
|           } |           } | ||||||
|           totwidth += 2; |           totwidth += 2; | ||||||
|             // start text at next char |           s = NULL;  // start text at next char | ||||||
|             s = NULL; |  | ||||||
|           width = 0; |           width = 0; | ||||||
|           } else { |  | ||||||
|             width += w; |  | ||||||
|           } |  | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -5415,6 +5415,45 @@ describe('builtin popupmenu', function() | |||||||
|         feed('<C-E><Esc>') |         feed('<C-E><Esc>') | ||||||
|       end) |       end) | ||||||
|  |  | ||||||
|  |       -- oldtest: Test_pum_highlights_match_with_abbr() | ||||||
|  |       it('can highlight matched text with abbr', function() | ||||||
|  |         exec([[ | ||||||
|  |           func Omni_test(findstart, base) | ||||||
|  |             if a:findstart | ||||||
|  |               return col(".") | ||||||
|  |             endif | ||||||
|  |             return { | ||||||
|  |                   \ 'words': [ | ||||||
|  |                   \ { 'word': 'foobar', 'abbr': "foobar\t\t!" }, | ||||||
|  |                   \ { 'word': 'foobaz', 'abbr': "foobaz\t\t!" }, | ||||||
|  |                   \]} | ||||||
|  |           endfunc | ||||||
|  |  | ||||||
|  |           set omnifunc=Omni_test | ||||||
|  |           set completeopt=menuone,noinsert | ||||||
|  |           hi PmenuMatchSel  guifg=Blue guibg=Grey | ||||||
|  |           hi PmenuMatch     guifg=Blue guibg=Plum1 | ||||||
|  |         ]]) | ||||||
|  |         feed('i<C-X><C-O>') | ||||||
|  |         screen:expect([[ | ||||||
|  |           ^                                | | ||||||
|  |           {s:foobar    !    }{1:                 }| | ||||||
|  |           {n:foobaz    !    }{1:                 }| | ||||||
|  |           {1:~                               }|*16 | ||||||
|  |           {2:-- }{5:match 1 of 2}                 | | ||||||
|  |         ]]) | ||||||
|  |         feed('foo') | ||||||
|  |         screen:expect([[ | ||||||
|  |           foo^                             | | ||||||
|  |           {ms:foo}{s:bar    !    }{1:                 }| | ||||||
|  |           {mn:foo}{n:baz    !    }{1:                 }| | ||||||
|  |           {1:~                               }|*16 | ||||||
|  |           {2:-- }{5:match 1 of 2}                 | | ||||||
|  |         ]]) | ||||||
|  |  | ||||||
|  |         feed('<C-E><Esc>') | ||||||
|  |       end) | ||||||
|  |  | ||||||
|       -- oldtest: Test_pum_user_abbr_hlgroup() |       -- oldtest: Test_pum_user_abbr_hlgroup() | ||||||
|       it('custom abbr_hlgroup override', function() |       it('custom abbr_hlgroup override', function() | ||||||
|         exec([[ |         exec([[ | ||||||
|   | |||||||
| @@ -1519,6 +1519,39 @@ func Test_pum_highlights_match() | |||||||
|   call StopVimInTerminal(buf) |   call StopVimInTerminal(buf) | ||||||
| endfunc | endfunc | ||||||
|  |  | ||||||
|  | func Test_pum_highlights_match_with_abbr() | ||||||
|  |   CheckScreendump | ||||||
|  |   let lines =<< trim END | ||||||
|  |     func Omni_test(findstart, base) | ||||||
|  |       if a:findstart | ||||||
|  |         return col(".") | ||||||
|  |       endif | ||||||
|  |       return { | ||||||
|  |             \ 'words': [ | ||||||
|  |             \ { 'word': 'foobar', 'abbr': "foobar\t\t!" }, | ||||||
|  |             \ { 'word': 'foobaz', 'abbr': "foobaz\t\t!" }, | ||||||
|  |             \]} | ||||||
|  |     endfunc | ||||||
|  |  | ||||||
|  |     set omnifunc=Omni_test | ||||||
|  |     set completeopt=menuone,noinsert | ||||||
|  |     hi PmenuMatchSel  ctermfg=6 ctermbg=7 | ||||||
|  |     hi PmenuMatch     ctermfg=4 ctermbg=225 | ||||||
|  |   END | ||||||
|  |   call writefile(lines, 'Xscript', 'D') | ||||||
|  |   let  buf = RunVimInTerminal('-S Xscript', {}) | ||||||
|  |   call TermWait(buf) | ||||||
|  |   call term_sendkeys(buf, "i\<C-X>\<C-O>") | ||||||
|  |   call TermWait(buf, 50) | ||||||
|  |   call term_sendkeys(buf, "foo") | ||||||
|  |   call VerifyScreenDump(buf, 'Test_pum_highlights_19', {}) | ||||||
|  |  | ||||||
|  |   call term_sendkeys(buf, "\<C-E>\<Esc>") | ||||||
|  |   call TermWait(buf) | ||||||
|  |  | ||||||
|  |   call StopVimInTerminal(buf) | ||||||
|  | endfunc | ||||||
|  |  | ||||||
| func Test_pum_user_abbr_hlgroup() | func Test_pum_user_abbr_hlgroup() | ||||||
|   CheckScreendump |   CheckScreendump | ||||||
|   let lines =<< trim END |   let lines =<< trim END | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 zeertzjq
					zeertzjq