mirror of
				https://github.com/neovim/neovim.git
				synced 2025-10-26 12:27:24 +00:00 
			
		
		
		
	Merge #9815 'vim-patch:8.1.1068: complete_info()'
This commit is contained in:
		| @@ -2021,6 +2021,7 @@ col({expr})			Number	column nr of cursor or mark | ||||
| complete({startcol}, {matches}) none	set Insert mode completion | ||||
| complete_add({expr})		Number	add completion match | ||||
| complete_check()		Number	check for key typed during completion | ||||
| complete_info([{what}])		Dict	get current completion information | ||||
| confirm({msg} [, {choices} [, {default} [, {type}]]]) | ||||
| 				Number	number of choice picked by user | ||||
| copy({expr})			any	make a shallow copy of {expr} | ||||
| @@ -2844,8 +2845,8 @@ cindent({lnum})						*cindent()* | ||||
| 		See |C-indenting|. | ||||
|  | ||||
| clearmatches()						*clearmatches()* | ||||
| 		Clears all matches previously defined by |matchadd()| and the | ||||
| 		|:match| commands. | ||||
| 		Clears all matches previously defined for the current window | ||||
| 		by |matchadd()| and the |:match| commands. | ||||
|  | ||||
| 							*col()* | ||||
| col({expr})	The result is a Number, which is the byte index of the column | ||||
| @@ -2930,6 +2931,55 @@ complete_check()				*complete_check()* | ||||
| 		Only to be used by the function specified with the | ||||
| 		'completefunc' option. | ||||
|  | ||||
| 							*complete_info()* | ||||
| complete_info([{what}]) | ||||
| 		Returns a Dictionary with information about Insert mode | ||||
| 		completion.  See |ins-completion|. | ||||
| 		The items are: | ||||
| 		   mode		Current completion mode name string. | ||||
| 				See |completion_info_mode| for the values. | ||||
| 		   pum_visible	|TRUE| if popup menu is visible. | ||||
| 				See |pumvisible()|. | ||||
| 		   items	List of completion matches.  Each item is a | ||||
| 				dictionary containing the entries "word", | ||||
| 				"abbr", "menu", "kind", "info" and "user_data". | ||||
| 				See |complete-items|. | ||||
| 		   selected	Selected item index.  First index is zero. | ||||
| 				Index is -1 if no item is selected (showing | ||||
| 				typed text only) | ||||
| 		   inserted	Inserted string. [NOT IMPLEMENT YET] | ||||
|  | ||||
| 							*complete_info_mode* | ||||
| 		mode values are: | ||||
| 		   ""		     Not in completion mode | ||||
| 		   "keyword"	     Keyword completion |i_CTRL-X_CTRL-N| | ||||
| 		   "ctrl_x"	     Just pressed CTRL-X |i_CTRL-X| | ||||
| 		   "whole_line"	     Whole lines |i_CTRL-X_CTRL-L| | ||||
| 		   "files"	     File names |i_CTRL-X_CTRL-F| | ||||
| 		   "tags"	     Tags |i_CTRL-X_CTRL-]| | ||||
| 		   "path_defines"    Definition completion |i_CTRL-X_CTRL-D| | ||||
| 		   "path_patterns"   Include completion |i_CTRL-X_CTRL-I| | ||||
| 		   "dictionary"	     Dictionary |i_CTRL-X_CTRL-K| | ||||
| 		   "thesaurus"	     Thesaurus |i_CTRL-X_CTRL-T| | ||||
| 		   "cmdline"	     Vim Command line |i_CTRL-X_CTRL-V| | ||||
| 		   "function"	     User defined completion |i_CTRL-X_CTRL-U| | ||||
| 		   "omni"	     Omni completion |i_CTRL-X_CTRL-O| | ||||
| 		   "spell"	     Spelling suggestions |i_CTRL-X_s| | ||||
| 		   "eval"            |complete()| completion | ||||
| 		   "unknown"	     Other internal modes | ||||
|  | ||||
| 		If the optional {what} list argument is supplied, then only | ||||
| 		the items listed in {what} are returned.  Unsupported items in | ||||
| 		{what} are silently ignored. | ||||
|  | ||||
| 		Examples: > | ||||
| 			" Get all items | ||||
| 			call complete_info() | ||||
| 			" Get only 'mode' | ||||
| 			call complete_info(['mode']) | ||||
| 			" Get only 'mode' and 'pum_visible' | ||||
| 			call complete_info(['mode', 'pum_visible']) | ||||
| < | ||||
| 						*confirm()* | ||||
| confirm({msg} [, {choices} [, {default} [, {type}]]]) | ||||
| 		Confirm() offers the user a dialog, from which a choice can be | ||||
| @@ -4279,10 +4329,11 @@ getloclist({nr},[, {what}])				*getloclist()* | ||||
| 		|getqflist()| for the supported items in {what}. | ||||
|  | ||||
| getmatches()						*getmatches()* | ||||
| 		Returns a |List| with all matches previously defined by | ||||
| 		|matchadd()| and the |:match| commands.  |getmatches()| is | ||||
| 		useful in combination with |setmatches()|, as |setmatches()| | ||||
| 		can restore a list of matches saved by |getmatches()|. | ||||
| 		Returns a |List| with all matches previously defined for the | ||||
| 		current window by |matchadd()| and the |:match| commands. | ||||
| 		|getmatches()| is useful in combination with |setmatches()|, | ||||
| 		as |setmatches()| can restore a list of matches saved by | ||||
| 		|getmatches()|. | ||||
| 		Example: > | ||||
| 			:echo getmatches() | ||||
| <			[{'group': 'MyGroup1', 'pattern': 'TODO', | ||||
| @@ -6862,9 +6913,10 @@ setloclist({nr}, {list} [, {action}[, {what}]])		*setloclist()* | ||||
| 		for the list of supported keys in {what}. | ||||
|  | ||||
| setmatches({list})					*setmatches()* | ||||
| 		Restores a list of matches saved by |getmatches()|.  Returns 0 | ||||
| 		if successful, otherwise -1.  All current matches are cleared | ||||
| 		before the list is restored.  See example for |getmatches()|. | ||||
| 		Restores a list of matches saved by |getmatches() for the | ||||
| 		current window|.  Returns 0 if successful, otherwise -1.  All | ||||
| 		current matches are cleared before the list is restored.  See | ||||
| 		example for |getmatches()|. | ||||
|  | ||||
| 							*setpos()* | ||||
| setpos({expr}, {list}) | ||||
|   | ||||
| @@ -359,8 +359,8 @@ CTRL-\ CTRL-O	like CTRL-O but don't move the cursor	     *i_CTRL-\_CTRL-O* | ||||
| CTRL-L		when 'insertmode' is set: go to Normal mode  *i_CTRL-L* | ||||
| CTRL-G u	break undo sequence, start new change	     *i_CTRL-G_u* | ||||
| CTRL-G U	don't break undo with next left/right cursor *i_CTRL-G_U* | ||||
| 		movement (but only if the cursor stays | ||||
| 		within same the line) | ||||
| 		movement, if the cursor stays within | ||||
| 		same the line | ||||
| ----------------------------------------------------------------------- | ||||
|  | ||||
| The CTRL-O command sometimes has a side effect: If the cursor was beyond the | ||||
| @@ -617,6 +617,7 @@ and one of the CTRL-X commands.  You exit CTRL-X mode by typing a key that is | ||||
| not a valid CTRL-X mode command.  Valid keys are the CTRL-X command itself, | ||||
| CTRL-N (next), and CTRL-P (previous). | ||||
|  | ||||
| To get the current completion information, |complete_info()| can be used. | ||||
| Also see the 'infercase' option if you want to adjust the case of the match. | ||||
|  | ||||
| 							*complete_CTRL-E* | ||||
|   | ||||
| @@ -825,6 +825,7 @@ Insert mode completion:				*completion-functions* | ||||
| 	complete()		set found matches | ||||
| 	complete_add()		add to found matches | ||||
| 	complete_check()	check if completion should be aborted | ||||
| 	complete_info()		get current completion information | ||||
| 	pumvisible()		check if the popup menu is displayed | ||||
|  | ||||
| Folding:					*folding-functions* | ||||
|   | ||||
| @@ -3246,7 +3246,7 @@ def CheckLanguage(filename, clean_lines, linenum, file_extension, | ||||
|                           r'|li_(?:next|prev|tv))\b', line) | ||||
|         if match: | ||||
|             error(filename, linenum, 'runtime/deprecated', 4, | ||||
|                   'Accessing list_T internals directly is prohibited') | ||||
|                   'Accessing list_T internals directly is prohibited (hint: see commit d46e37cb4c71)') | ||||
|  | ||||
|     # Check for suspicious usage of "if" like | ||||
|     # } if (a == b) { | ||||
|   | ||||
							
								
								
									
										128
									
								
								src/nvim/edit.c
									
									
									
									
									
								
							
							
						
						
									
										128
									
								
								src/nvim/edit.c
									
									
									
									
									
								
							| @@ -58,9 +58,10 @@ | ||||
| #include "nvim/os/input.h" | ||||
| #include "nvim/os/time.h" | ||||
|  | ||||
| /* | ||||
|  * definitions used for CTRL-X submode | ||||
|  */ | ||||
| // Definitions used for CTRL-X submode. | ||||
| // Note: If you change CTRL-X submode, you must also maintain ctrl_x_msgs[] | ||||
| // and ctrl_x_mode_names[]. | ||||
|  | ||||
| #define CTRL_X_WANT_IDENT       0x100 | ||||
|  | ||||
| #define CTRL_X_NOT_DEFINED_YET  1 | ||||
| @@ -83,17 +84,18 @@ | ||||
| #define CTRL_X_MSG(i) ctrl_x_msgs[(i) & ~CTRL_X_WANT_IDENT] | ||||
| #define CTRL_X_MODE_LINE_OR_EVAL(m) (m == CTRL_X_WHOLE_LINE || m == CTRL_X_EVAL) | ||||
|  | ||||
| // Message for CTRL-X mode, index is ctrl_x_mode. | ||||
| static char *ctrl_x_msgs[] = | ||||
| { | ||||
|   N_(" Keyword completion (^N^P)"),   /* ctrl_x_mode == 0, ^P/^N compl. */ | ||||
|   N_(" Keyword completion (^N^P)"),  // CTRL_X_NORMAL, ^P/^N compl. | ||||
|   N_(" ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"), | ||||
|   NULL, | ||||
|   NULL,  // CTRL_X_SCROLL: depends on state | ||||
|   N_(" Whole line completion (^L^N^P)"), | ||||
|   N_(" File name completion (^F^N^P)"), | ||||
|   N_(" Tag completion (^]^N^P)"), | ||||
|   N_(" Path pattern completion (^N^P)"), | ||||
|   N_(" Definition completion (^D^N^P)"), | ||||
|   NULL, | ||||
|   NULL,  // CTRL_X_FINISHED | ||||
|   N_(" Dictionary completion (^K^N^P)"), | ||||
|   N_(" Thesaurus completion (^T^N^P)"), | ||||
|   N_(" Command-line completion (^V^N^P)"), | ||||
| @@ -104,6 +106,26 @@ static char *ctrl_x_msgs[] = | ||||
|   NULL,  // CTRL_X_EVAL doesn't use msg. | ||||
| }; | ||||
|  | ||||
| static char *ctrl_x_mode_names[] = { | ||||
|   "keyword", | ||||
|   "ctrl_x", | ||||
|   "unknown",          // CTRL_X_SCROLL | ||||
|   "whole_line", | ||||
|   "files", | ||||
|   "tags", | ||||
|   "path_patterns", | ||||
|   "path_defines", | ||||
|   "unknown",          // CTRL_X_FINISHED | ||||
|   "dictionary", | ||||
|   "thesaurus", | ||||
|   "cmdline", | ||||
|   "function", | ||||
|   "omni", | ||||
|   "spell", | ||||
|   NULL,               // CTRL_X_LOCAL_MSG only used in "ctrl_x_msgs" | ||||
|   "eval" | ||||
| }; | ||||
|  | ||||
| static char e_hitend[] = N_("Hit end of paragraph"); | ||||
| static char e_complwin[] = N_("E839: Completion function changed window"); | ||||
| static char e_compldel[] = N_("E840: Completion function deleted text"); | ||||
| @@ -2980,6 +3002,100 @@ bool ins_compl_active(void) | ||||
|   return compl_started; | ||||
| } | ||||
|  | ||||
| // Get complete information | ||||
| void get_complete_info(list_T *what_list, dict_T *retdict) | ||||
| { | ||||
|   int ret = OK; | ||||
| #define CI_WHAT_MODE            0x01 | ||||
| #define CI_WHAT_PUM_VISIBLE     0x02 | ||||
| #define CI_WHAT_ITEMS           0x04 | ||||
| #define CI_WHAT_SELECTED        0x08 | ||||
| #define CI_WHAT_INSERTED        0x10 | ||||
| #define CI_WHAT_ALL             0xff | ||||
|   int what_flag; | ||||
|  | ||||
|   if (what_list == NULL) { | ||||
|     what_flag = CI_WHAT_ALL; | ||||
|   } else { | ||||
|     what_flag = 0; | ||||
|     for (listitem_T *item = TV_LIST_ITEM_NEXT(what_list, | ||||
|                                               tv_list_first(what_list)) | ||||
|          ; item != NULL | ||||
|          ; item = TV_LIST_ITEM_NEXT(what_list, item)) { | ||||
|       const char *what = tv_get_string(TV_LIST_ITEM_TV(item)); | ||||
|  | ||||
|       if (STRCMP(what, "mode") == 0) { | ||||
|         what_flag |= CI_WHAT_MODE; | ||||
|       } else if (STRCMP(what, "pum_visible") == 0) { | ||||
|         what_flag |= CI_WHAT_PUM_VISIBLE; | ||||
|       } else if (STRCMP(what, "items") == 0) { | ||||
|         what_flag |= CI_WHAT_ITEMS; | ||||
|       } else if (STRCMP(what, "selected") == 0) { | ||||
|         what_flag |= CI_WHAT_SELECTED; | ||||
|       } else if (STRCMP(what, "inserted") == 0) { | ||||
|         what_flag |= CI_WHAT_INSERTED; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   if (ret == OK && (what_flag & CI_WHAT_MODE)) { | ||||
|     ret = tv_dict_add_str(retdict, S_LEN("mode"), | ||||
|                           (const char *)ins_compl_mode()); | ||||
|   } | ||||
|  | ||||
|   if (ret == OK && (what_flag & CI_WHAT_PUM_VISIBLE)) { | ||||
|     ret = tv_dict_add_nr(retdict, S_LEN("pum_visible"), pum_visible()); | ||||
|   } | ||||
|  | ||||
|   if (ret == OK && (what_flag & CI_WHAT_ITEMS)) { | ||||
|     list_T *li = tv_list_alloc(ins_compl_len()); | ||||
|  | ||||
|     ret = tv_dict_add_list(retdict, S_LEN("items"), li); | ||||
|     if (ret == OK && compl_first_match != NULL) { | ||||
|       compl_T *match = compl_first_match; | ||||
|       do { | ||||
|         if (!(match->cp_flags & ORIGINAL_TEXT)) { | ||||
|           dict_T *di = tv_dict_alloc(); | ||||
|  | ||||
|           tv_list_append_dict(li, di); | ||||
|           tv_dict_add_str(di, S_LEN("word"), | ||||
|                           (const char *)match->cp_str); | ||||
|           tv_dict_add_str(di, S_LEN("abbr"), | ||||
|                           (const char *)match->cp_text[CPT_ABBR]); | ||||
|           tv_dict_add_str(di, S_LEN("menu"), | ||||
|                           (const char *)match->cp_text[CPT_MENU]); | ||||
|           tv_dict_add_str(di, S_LEN("kind"), | ||||
|                           (const char *)match->cp_text[CPT_KIND]); | ||||
|           tv_dict_add_str(di, S_LEN("info"), | ||||
|                           (const char *)match->cp_text[CPT_INFO]); | ||||
|           tv_dict_add_str(di, S_LEN("user_data"), | ||||
|                           (const char *)match->cp_text[CPT_USER_DATA]); | ||||
|         } | ||||
|         match = match->cp_next; | ||||
|       } while (match != NULL && match != compl_first_match); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   if (ret == OK && (what_flag & CI_WHAT_SELECTED)) { | ||||
|     ret = tv_dict_add_nr(retdict, S_LEN("selected"), | ||||
|                          (compl_curr_match != NULL) | ||||
|                          ? compl_curr_match->cp_number - 1 : -1); | ||||
|   } | ||||
|  | ||||
|   // TODO(vim): | ||||
|   // if (ret == OK && (what_flag & CI_WHAT_INSERTED)) | ||||
| } | ||||
|  | ||||
| // Return Insert completion mode name string | ||||
| static char_u * ins_compl_mode(void) | ||||
| { | ||||
|     if (ctrl_x_mode == CTRL_X_NOT_DEFINED_YET || compl_started) { | ||||
|       return (char_u *)ctrl_x_mode_names[ctrl_x_mode & ~CTRL_X_WANT_IDENT]; | ||||
|     } | ||||
|     return (char_u *)""; | ||||
| } | ||||
|  | ||||
|  | ||||
| /* | ||||
|  * Delete one character before the cursor and show the subset of the matches | ||||
|  * that match the word that is now before the cursor. | ||||
|   | ||||
| @@ -7564,6 +7564,23 @@ static void f_complete_check(typval_T *argvars, typval_T *rettv, FunPtr fptr) | ||||
|   RedrawingDisabled = saved; | ||||
| } | ||||
|  | ||||
| // "complete_info()" function | ||||
| static void f_complete_info(typval_T *argvars, typval_T *rettv, FunPtr fptr) | ||||
| { | ||||
|   tv_dict_alloc_ret(rettv); | ||||
|  | ||||
|   list_T *what_list = NULL; | ||||
|  | ||||
|   if (argvars[0].v_type != VAR_UNKNOWN) { | ||||
|     if (argvars[0].v_type != VAR_LIST) { | ||||
|       EMSG(_(e_listreq)); | ||||
|       return; | ||||
|     } | ||||
|     what_list = argvars[0].vval.v_list; | ||||
|   } | ||||
|   get_complete_info(what_list, rettv->vval.v_dict); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * "confirm(message, buttons[, default [, type]])" function | ||||
|  */ | ||||
|   | ||||
| @@ -64,6 +64,7 @@ return { | ||||
|     complete={args=2}, | ||||
|     complete_add={args=1}, | ||||
|     complete_check={}, | ||||
|     complete_info={args={0, 1}}, | ||||
|     confirm={args={1, 4}}, | ||||
|     copy={args=1}, | ||||
|     cos={args=1, func="float_op_wrapper", data="&cos"}, | ||||
|   | ||||
| @@ -712,4 +712,105 @@ func Test_popup_and_window_resize() | ||||
|   bwipe! | ||||
| endfunc | ||||
|  | ||||
| func Test_popup_complete_info_01() | ||||
|   new | ||||
|   inoremap <buffer><F5> <C-R>=complete_info().mode<CR> | ||||
|   func s:complTestEval() abort | ||||
|     call complete(1, ['aa', 'ab']) | ||||
|     return '' | ||||
|   endfunc | ||||
|   inoremap <buffer><F6> <C-R>=s:complTestEval()<CR> | ||||
|   call writefile([ | ||||
|         \ 'dummy	dummy.txt	1', | ||||
|         \], 'Xdummy.txt') | ||||
|   setlocal tags=Xdummy.txt | ||||
|   setlocal dictionary=Xdummy.txt | ||||
|   setlocal thesaurus=Xdummy.txt | ||||
|   setlocal omnifunc=syntaxcomplete#Complete | ||||
|   setlocal completefunc=syntaxcomplete#Complete | ||||
|   setlocal spell | ||||
|   for [keys, mode_name] in [ | ||||
|         \ ["", ''], | ||||
|         \ ["\<C-X>", 'ctrl_x'], | ||||
|         \ ["\<C-X>\<C-N>", 'keyword'], | ||||
|         \ ["\<C-X>\<C-P>", 'keyword'], | ||||
|         \ ["\<C-X>\<C-L>", 'whole_line'], | ||||
|         \ ["\<C-X>\<C-F>", 'files'], | ||||
|         \ ["\<C-X>\<C-]>", 'tags'], | ||||
|         \ ["\<C-X>\<C-D>", 'path_defines'], | ||||
|         \ ["\<C-X>\<C-I>", 'path_patterns'], | ||||
|         \ ["\<C-X>\<C-K>", 'dictionary'], | ||||
|         \ ["\<C-X>\<C-T>", 'thesaurus'], | ||||
|         \ ["\<C-X>\<C-V>", 'cmdline'], | ||||
|         \ ["\<C-X>\<C-U>", 'function'], | ||||
|         \ ["\<C-X>\<C-O>", 'omni'], | ||||
|         \ ["\<C-X>s", 'spell'], | ||||
|         \ ["\<F6>", 'eval'], | ||||
|         \] | ||||
|     call feedkeys("i" . keys . "\<F5>\<Esc>", 'tx') | ||||
|     call assert_equal(mode_name, getline('.')) | ||||
|     %d | ||||
|   endfor | ||||
|   call delete('Xdummy.txt') | ||||
|   bwipe! | ||||
| endfunc | ||||
|  | ||||
| func UserDefinedComplete(findstart, base) | ||||
|   if a:findstart | ||||
|     return 0 | ||||
|   else | ||||
|     return [ | ||||
|           \   { 'word': 'Jan', 'menu': 'January' }, | ||||
|           \   { 'word': 'Feb', 'menu': 'February' }, | ||||
|           \   { 'word': 'Mar', 'menu': 'March' }, | ||||
|           \   { 'word': 'Apr', 'menu': 'April' }, | ||||
|           \   { 'word': 'May', 'menu': 'May' }, | ||||
|           \ ] | ||||
|   endif | ||||
| endfunc | ||||
|  | ||||
| func GetCompleteInfo() | ||||
|   if empty(g:compl_what) | ||||
|     let g:compl_info = complete_info() | ||||
|   else | ||||
|     let g:compl_info = complete_info(g:compl_what) | ||||
|   endif | ||||
|   return '' | ||||
| endfunc | ||||
|  | ||||
| func Test_popup_complete_info_02() | ||||
|   new | ||||
|   inoremap <buffer><F5> <C-R>=GetCompleteInfo()<CR> | ||||
|   setlocal completefunc=UserDefinedComplete | ||||
|  | ||||
|   let d = { | ||||
|     \   'mode': 'function', | ||||
|     \   'pum_visible': 1, | ||||
|     \   'items': [ | ||||
|     \     {'word': 'Jan', 'menu': 'January', 'user_data': '', 'info': '', 'kind': '', 'abbr': ''}, | ||||
|     \     {'word': 'Feb', 'menu': 'February', 'user_data': '', 'info': '', 'kind': '', 'abbr': ''}, | ||||
|     \     {'word': 'Mar', 'menu': 'March', 'user_data': '', 'info': '', 'kind': '', 'abbr': ''}, | ||||
|     \     {'word': 'Apr', 'menu': 'April', 'user_data': '', 'info': '', 'kind': '', 'abbr': ''}, | ||||
|     \     {'word': 'May', 'menu': 'May', 'user_data': '', 'info': '', 'kind': '', 'abbr': ''} | ||||
|     \   ], | ||||
|     \   'selected': 0, | ||||
|     \ } | ||||
|  | ||||
|   let g:compl_what = [] | ||||
|   call feedkeys("i\<C-X>\<C-U>\<F5>", 'tx') | ||||
|   call assert_equal(d, g:compl_info) | ||||
|  | ||||
|   let g:compl_what = ['mode', 'pum_visible', 'selected'] | ||||
|   call remove(d, 'items') | ||||
|   call feedkeys("i\<C-X>\<C-U>\<F5>", 'tx') | ||||
|   call assert_equal(d, g:compl_info) | ||||
|  | ||||
|   let g:compl_what = ['mode'] | ||||
|   call remove(d, 'selected') | ||||
|   call remove(d, 'pum_visible') | ||||
|   call feedkeys("i\<C-X>\<C-U>\<F5>", 'tx') | ||||
|   call assert_equal(d, g:compl_info) | ||||
|   bwipe! | ||||
| endfunc | ||||
|  | ||||
| " vim: shiftwidth=2 sts=2 expandtab | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Justin M. Keyes
					Justin M. Keyes