mirror of
				https://github.com/neovim/neovim.git
				synced 2025-10-26 12:27:24 +00:00 
			
		
		
		
	get_keymap API (#6236)
* Add api function get keymap nvim_get_keymap(mode) nvim_buf_get_keymap(buffer, mode)
This commit is contained in:
		| @@ -453,6 +453,26 @@ Integer nvim_buf_get_changedtick(Buffer buffer, Error *err) | |||||||
|   return buf->b_changedtick; |   return buf->b_changedtick; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /// Get a list of dictionaries describing buffer-local mappings | ||||||
|  | /// Note that the buffer key in the dictionary will represent the buffer | ||||||
|  | /// handle where the mapping is present | ||||||
|  | /// | ||||||
|  | /// @param  mode  The abbreviation for the mode | ||||||
|  | /// @param  buffer_id  Buffer handle | ||||||
|  | /// @param[out]  err   Error details, if any | ||||||
|  | /// @returns An array of maparg() like dictionaries describing mappings | ||||||
|  | ArrayOf(Dictionary) nvim_buf_get_keymap(Buffer buffer, String mode, Error *err) | ||||||
|  |     FUNC_API_SINCE(3) | ||||||
|  | { | ||||||
|  |   buf_T *buf = find_buffer_by_handle(buffer, err); | ||||||
|  |  | ||||||
|  |   if (!buf) { | ||||||
|  |     return (Array)ARRAY_DICT_INIT; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   return keymap_array(mode, buf); | ||||||
|  | } | ||||||
|  |  | ||||||
| /// Sets a buffer-scoped (b:) variable | /// Sets a buffer-scoped (b:) variable | ||||||
| /// | /// | ||||||
| /// @param buffer     Buffer handle | /// @param buffer     Buffer handle | ||||||
|   | |||||||
| @@ -24,6 +24,7 @@ | |||||||
| #include "nvim/option_defs.h" | #include "nvim/option_defs.h" | ||||||
| #include "nvim/version.h" | #include "nvim/version.h" | ||||||
| #include "nvim/lib/kvec.h" | #include "nvim/lib/kvec.h" | ||||||
|  | #include "nvim/getchar.h" | ||||||
|  |  | ||||||
| /// Helper structure for vim_to_object | /// Helper structure for vim_to_object | ||||||
| typedef struct { | typedef struct { | ||||||
| @@ -1034,3 +1035,41 @@ void api_set_error(Error *err, ErrorType errType, const char *format, ...) | |||||||
|  |  | ||||||
|   err->type = errType; |   err->type = errType; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /// Get an array containing dictionaries describing mappings | ||||||
|  | /// based on mode and buffer id | ||||||
|  | /// | ||||||
|  | /// @param  mode  The abbreviation for the mode | ||||||
|  | /// @param  buf  The buffer to get the mapping array. NULL for global | ||||||
|  | /// @returns An array of maparg() like dictionaries describing mappings | ||||||
|  | ArrayOf(Dictionary) keymap_array(String mode, buf_T *buf) | ||||||
|  | { | ||||||
|  |   Array mappings = ARRAY_DICT_INIT; | ||||||
|  |   dict_T *const dict = tv_dict_alloc(); | ||||||
|  |  | ||||||
|  |   // Convert the string mode to the integer mode | ||||||
|  |   // that is stored within each mapblock | ||||||
|  |   char_u *p = (char_u *)mode.data; | ||||||
|  |   int int_mode = get_map_mode(&p, 0); | ||||||
|  |  | ||||||
|  |   // Determine the desired buffer value | ||||||
|  |   long buffer_value = (buf == NULL) ? 0 : buf->handle; | ||||||
|  |  | ||||||
|  |   for (int i = 0; i < MAX_MAPHASH; i++) { | ||||||
|  |     for (const mapblock_T *current_maphash = get_maphash(i, buf); | ||||||
|  |          current_maphash; | ||||||
|  |          current_maphash = current_maphash->m_next) { | ||||||
|  |       // Check for correct mode | ||||||
|  |       if (int_mode & current_maphash->m_mode) { | ||||||
|  |         mapblock_fill_dict(dict, current_maphash, buffer_value, false); | ||||||
|  |         ADD(mappings, vim_to_object( | ||||||
|  |             (typval_T[]) { { .v_type = VAR_DICT, .vval.v_dict = dict } })); | ||||||
|  |  | ||||||
|  |         tv_dict_clear(dict); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   tv_dict_free(dict); | ||||||
|  |  | ||||||
|  |   return mappings; | ||||||
|  | } | ||||||
|   | |||||||
| @@ -742,6 +742,17 @@ Dictionary nvim_get_mode(void) | |||||||
|   return rv; |   return rv; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /// Get a list of dictionaries describing global (i.e. non-buffer) mappings | ||||||
|  | /// Note that the "buffer" key will be 0 to represent false. | ||||||
|  | /// | ||||||
|  | /// @param  mode  The abbreviation for the mode | ||||||
|  | /// @returns  An array of maparg() like dictionaries describing mappings | ||||||
|  | ArrayOf(Dictionary) nvim_get_keymap(String mode) | ||||||
|  |     FUNC_API_SINCE(3) | ||||||
|  | { | ||||||
|  |   return keymap_array(mode, NULL); | ||||||
|  | } | ||||||
|  |  | ||||||
| Array nvim_get_api_info(uint64_t channel_id) | Array nvim_get_api_info(uint64_t channel_id) | ||||||
|     FUNC_API_SINCE(1) FUNC_API_ASYNC FUNC_API_REMOTE_ONLY |     FUNC_API_SINCE(1) FUNC_API_ASYNC FUNC_API_REMOTE_ONLY | ||||||
| { | { | ||||||
|   | |||||||
| @@ -438,6 +438,9 @@ typedef TV_DICTITEM_STRUCT(sizeof("changedtick")) ChangedtickDictItem; | |||||||
| #define BUF_HAS_QF_ENTRY 1 | #define BUF_HAS_QF_ENTRY 1 | ||||||
| #define BUF_HAS_LL_ENTRY 2 | #define BUF_HAS_LL_ENTRY 2 | ||||||
|  |  | ||||||
|  | // Maximum number of maphash blocks we will have | ||||||
|  | #define MAX_MAPHASH 256 | ||||||
|  |  | ||||||
| /* | /* | ||||||
|  * buffer: structure that holds information about one file |  * buffer: structure that holds information about one file | ||||||
|  * |  * | ||||||
| @@ -526,8 +529,8 @@ struct file_buffer { | |||||||
|    */ |    */ | ||||||
|   uint64_t b_chartab[4]; |   uint64_t b_chartab[4]; | ||||||
|  |  | ||||||
|   /* Table used for mappings local to a buffer. */ |   // Table used for mappings local to a buffer. | ||||||
|   mapblock_T  *(b_maphash[256]); |   mapblock_T  *(b_maphash[MAX_MAPHASH]); | ||||||
|  |  | ||||||
|   /* First abbreviation local to a buffer. */ |   /* First abbreviation local to a buffer. */ | ||||||
|   mapblock_T  *b_first_abbr; |   mapblock_T  *b_first_abbr; | ||||||
|   | |||||||
| @@ -12102,22 +12102,7 @@ static void get_maparg(typval_T *argvars, typval_T *rettv, int exact) | |||||||
|     tv_dict_alloc_ret(rettv); |     tv_dict_alloc_ret(rettv); | ||||||
|     if (rhs != NULL) { |     if (rhs != NULL) { | ||||||
|       // Return a dictionary. |       // Return a dictionary. | ||||||
|       char_u *lhs = str2special_save(mp->m_keys, true); |       mapblock_fill_dict(rettv->vval.v_dict, mp, buffer_local, true); | ||||||
|       char *const mapmode = map_mode_to_chars(mp->m_mode); |  | ||||||
|       dict_T *dict = rettv->vval.v_dict; |  | ||||||
|  |  | ||||||
|       tv_dict_add_str(dict, S_LEN("lhs"), (const char *)lhs); |  | ||||||
|       tv_dict_add_str(dict, S_LEN("rhs"), (const char *)mp->m_orig_str); |  | ||||||
|       tv_dict_add_nr(dict, S_LEN("noremap"), mp->m_noremap ? 1 : 0); |  | ||||||
|       tv_dict_add_nr(dict, S_LEN("expr"),  mp->m_expr ? 1 : 0); |  | ||||||
|       tv_dict_add_nr(dict, S_LEN("silent"), mp->m_silent ? 1 : 0); |  | ||||||
|       tv_dict_add_nr(dict, S_LEN("sid"), (varnumber_T)mp->m_script_ID); |  | ||||||
|       tv_dict_add_nr(dict, S_LEN("buffer"), (varnumber_T)buffer_local); |  | ||||||
|       tv_dict_add_nr(dict, S_LEN("nowait"), mp->m_nowait ? 1 : 0); |  | ||||||
|       tv_dict_add_str(dict, S_LEN("mode"), mapmode); |  | ||||||
|  |  | ||||||
|       xfree(lhs); |  | ||||||
|       xfree(mapmode); |  | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| } | } | ||||||
| @@ -12134,6 +12119,46 @@ static void f_luaeval(typval_T *argvars, typval_T *rettv, FunPtr fptr) | |||||||
|   executor_eval_lua(cstr_as_string((char *)str), &argvars[1], rettv); |   executor_eval_lua(cstr_as_string((char *)str), &argvars[1], rettv); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /// Fill a dictionary with all applicable maparg() like dictionaries | ||||||
|  | /// | ||||||
|  | /// @param  dict  The dictionary to be filled | ||||||
|  | /// @param  mp  The maphash that contains the mapping information | ||||||
|  | /// @param  buffer_value  The "buffer" value | ||||||
|  | /// @param  compatible  True for compatible with old maparg() dict | ||||||
|  | void mapblock_fill_dict(dict_T *const dict, | ||||||
|  |                         const mapblock_T *const mp, | ||||||
|  |                         long buffer_value, | ||||||
|  |                         bool compatible) | ||||||
|  |     FUNC_ATTR_NONNULL_ALL | ||||||
|  | { | ||||||
|  |   char_u *lhs = str2special_save(mp->m_keys, true); | ||||||
|  |   char *const mapmode = map_mode_to_chars(mp->m_mode); | ||||||
|  |   varnumber_T noremap_value; | ||||||
|  |  | ||||||
|  |   if (compatible) { | ||||||
|  |     // Keep old compatible behavior | ||||||
|  |     // This is unable to determine whether a mapping is a <script> mapping | ||||||
|  |     noremap_value = !!mp->m_noremap; | ||||||
|  |   } else { | ||||||
|  |     // Distinguish between <script> mapping | ||||||
|  |     // If it's not a <script> mapping, check if it's a noremap | ||||||
|  |     noremap_value = mp->m_noremap == REMAP_SCRIPT ? 2 : !!mp->m_noremap; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   tv_dict_add_str(dict, S_LEN("lhs"), (const char *)lhs); | ||||||
|  |   tv_dict_add_str(dict, S_LEN("rhs"), (const char *)mp->m_orig_str); | ||||||
|  |   tv_dict_add_nr(dict, S_LEN("noremap"), noremap_value); | ||||||
|  |   tv_dict_add_nr(dict, S_LEN("expr"),  mp->m_expr ? 1 : 0); | ||||||
|  |   tv_dict_add_nr(dict, S_LEN("silent"), mp->m_silent ? 1 : 0); | ||||||
|  |   tv_dict_add_nr(dict, S_LEN("sid"), (varnumber_T)mp->m_script_ID); | ||||||
|  |   tv_dict_add_nr(dict, S_LEN("buffer"), (varnumber_T)buffer_value); | ||||||
|  |   tv_dict_add_nr(dict, S_LEN("nowait"), mp->m_nowait ? 1 : 0); | ||||||
|  |   tv_dict_add_str(dict, S_LEN("mode"), mapmode); | ||||||
|  |  | ||||||
|  |   xfree(lhs); | ||||||
|  |   xfree(mapmode); | ||||||
|  | } | ||||||
|  |  | ||||||
| /* | /* | ||||||
|  * "map()" function |  * "map()" function | ||||||
|  */ |  */ | ||||||
|   | |||||||
| @@ -18,6 +18,7 @@ | |||||||
| #include "nvim/vim.h" | #include "nvim/vim.h" | ||||||
| #include "nvim/ascii.h" | #include "nvim/ascii.h" | ||||||
| #include "nvim/getchar.h" | #include "nvim/getchar.h" | ||||||
|  | #include "nvim/buffer_defs.h" | ||||||
| #include "nvim/charset.h" | #include "nvim/charset.h" | ||||||
| #include "nvim/cursor.h" | #include "nvim/cursor.h" | ||||||
| #include "nvim/edit.h" | #include "nvim/edit.h" | ||||||
| @@ -47,6 +48,7 @@ | |||||||
| #include "nvim/event/loop.h" | #include "nvim/event/loop.h" | ||||||
| #include "nvim/os/input.h" | #include "nvim/os/input.h" | ||||||
| #include "nvim/os/os.h" | #include "nvim/os/os.h" | ||||||
|  | #include "nvim/api/private/handle.h" | ||||||
|  |  | ||||||
| /* | /* | ||||||
|  * These buffers are used for storing: |  * These buffers are used for storing: | ||||||
| @@ -102,11 +104,10 @@ static int block_redo = FALSE; | |||||||
|                        (NORMAL + VISUAL + SELECTMODE + \ |                        (NORMAL + VISUAL + SELECTMODE + \ | ||||||
|                         OP_PENDING)) ? (c1) : ((c1) ^ 0x80)) |                         OP_PENDING)) ? (c1) : ((c1) ^ 0x80)) | ||||||
|  |  | ||||||
| /* | // Each mapping is put in one of the MAX_MAPHASH hash lists, | ||||||
|  * Each mapping is put in one of the 256 hash lists, to speed up finding it. | // to speed up finding it. | ||||||
|  */ | static mapblock_T *(maphash[MAX_MAPHASH]); | ||||||
| static mapblock_T       *(maphash[256]); | static bool maphash_valid = false; | ||||||
| static int maphash_valid = FALSE; |  | ||||||
|  |  | ||||||
| /* | /* | ||||||
|  * List used for abbreviations. |  * List used for abbreviations. | ||||||
| @@ -4237,3 +4238,17 @@ static bool typebuf_match_len(const uint8_t *str, int *mlen) | |||||||
|   *mlen = i; |   *mlen = i; | ||||||
|   return str[i] == NUL;  // matched the whole string |   return str[i] == NUL;  // matched the whole string | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /// Retrieve the mapblock at the index either globally or for a certain buffer | ||||||
|  | /// | ||||||
|  | /// @param  index  The index in the maphash[] | ||||||
|  | /// @param  buf  The buffer to get the maphash from. NULL for global | ||||||
|  | mapblock_T *get_maphash(int index, buf_T *buf) | ||||||
|  |     FUNC_ATTR_PURE | ||||||
|  | { | ||||||
|  |   if (index > MAX_MAPHASH) { | ||||||
|  |     return NULL; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   return (buf == NULL) ? maphash[index] : buf->b_maphash[index]; | ||||||
|  | } | ||||||
|   | |||||||
							
								
								
									
										246
									
								
								test/functional/api/keymap_spec.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										246
									
								
								test/functional/api/keymap_spec.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,246 @@ | |||||||
|  |  | ||||||
|  | local helpers = require('test.functional.helpers')(after_each) | ||||||
|  | local clear = helpers.clear | ||||||
|  | local command = helpers.command | ||||||
|  | local curbufmeths = helpers.curbufmeths | ||||||
|  | local eq = helpers.eq | ||||||
|  | local funcs = helpers.funcs | ||||||
|  | local meths = helpers.meths | ||||||
|  | local source = helpers.source | ||||||
|  |  | ||||||
|  | local function local_copy(t) | ||||||
|  |   local copy = {} | ||||||
|  |   for k,v in pairs(t) do | ||||||
|  |     copy[k] = v | ||||||
|  |   end | ||||||
|  |   return copy | ||||||
|  | end | ||||||
|  |  | ||||||
|  | describe('get_keymap', function() | ||||||
|  |   before_each(clear) | ||||||
|  |  | ||||||
|  |   -- Basic mapping and table to be used to describe results | ||||||
|  |   local foo_bar_string = 'nnoremap foo bar' | ||||||
|  |   local foo_bar_map_table = { | ||||||
|  |       lhs='foo', | ||||||
|  |       silent=0, | ||||||
|  |       rhs='bar', | ||||||
|  |       expr=0, | ||||||
|  |       sid=0, | ||||||
|  |       buffer=0, | ||||||
|  |       nowait=0, | ||||||
|  |       mode='n', | ||||||
|  |       noremap=1, | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |   it('returns empty list when no map', function() | ||||||
|  |     eq({}, meths.get_keymap('n')) | ||||||
|  |   end) | ||||||
|  |  | ||||||
|  |   it('returns list of all applicable mappings', function() | ||||||
|  |     command(foo_bar_string) | ||||||
|  |     -- Only one mapping available | ||||||
|  |     -- Should be the same as the dictionary we supplied earlier | ||||||
|  |     -- and the dictionary you would get from maparg | ||||||
|  |     -- since this is a global map, and not script local | ||||||
|  |     eq({foo_bar_map_table}, meths.get_keymap('n')) | ||||||
|  |     eq({funcs.maparg('foo', 'n', false, true)}, | ||||||
|  |       meths.get_keymap('n') | ||||||
|  |     ) | ||||||
|  |  | ||||||
|  |     -- Add another mapping | ||||||
|  |     command('nnoremap foo_longer bar_longer') | ||||||
|  |     local foolong_bar_map_table = local_copy(foo_bar_map_table) | ||||||
|  |     foolong_bar_map_table['lhs'] = 'foo_longer' | ||||||
|  |     foolong_bar_map_table['rhs'] = 'bar_longer' | ||||||
|  |  | ||||||
|  |     eq({foolong_bar_map_table, foo_bar_map_table}, | ||||||
|  |       meths.get_keymap('n') | ||||||
|  |     ) | ||||||
|  |  | ||||||
|  |     -- Remove a mapping | ||||||
|  |     command('unmap foo_longer') | ||||||
|  |     eq({foo_bar_map_table}, | ||||||
|  |       meths.get_keymap('n') | ||||||
|  |     ) | ||||||
|  |   end) | ||||||
|  |  | ||||||
|  |   it('works for other modes', function() | ||||||
|  |     -- Add two mappings, one in insert and one normal | ||||||
|  |     -- We'll only check the insert mode one | ||||||
|  |     command('nnoremap not_going to_check') | ||||||
|  |  | ||||||
|  |     command('inoremap foo bar') | ||||||
|  |     -- The table will be the same except for the mode | ||||||
|  |     local insert_table = local_copy(foo_bar_map_table) | ||||||
|  |     insert_table['mode'] = 'i' | ||||||
|  |  | ||||||
|  |     eq({insert_table}, meths.get_keymap('i')) | ||||||
|  |   end) | ||||||
|  |  | ||||||
|  |   it('considers scope', function() | ||||||
|  |     -- change the map slightly | ||||||
|  |     command('nnoremap foo_longer bar_longer') | ||||||
|  |     local foolong_bar_map_table = local_copy(foo_bar_map_table) | ||||||
|  |     foolong_bar_map_table['lhs'] = 'foo_longer' | ||||||
|  |     foolong_bar_map_table['rhs'] = 'bar_longer' | ||||||
|  |  | ||||||
|  |     local buffer_table = local_copy(foo_bar_map_table) | ||||||
|  |     buffer_table['buffer'] = 1 | ||||||
|  |  | ||||||
|  |     command('nnoremap <buffer> foo bar') | ||||||
|  |  | ||||||
|  |     -- The buffer mapping should not show up | ||||||
|  |     eq({foolong_bar_map_table}, meths.get_keymap('n')) | ||||||
|  |     eq({buffer_table}, curbufmeths.get_keymap('n')) | ||||||
|  |   end) | ||||||
|  |  | ||||||
|  |   it('considers scope for overlapping maps', function() | ||||||
|  |     command('nnoremap foo bar') | ||||||
|  |  | ||||||
|  |     local buffer_table = local_copy(foo_bar_map_table) | ||||||
|  |     buffer_table['buffer'] = 1 | ||||||
|  |  | ||||||
|  |     command('nnoremap <buffer> foo bar') | ||||||
|  |  | ||||||
|  |     eq({foo_bar_map_table}, meths.get_keymap('n')) | ||||||
|  |     eq({buffer_table}, curbufmeths.get_keymap('n')) | ||||||
|  |   end) | ||||||
|  |  | ||||||
|  |   it('can retrieve mapping for different buffers', function() | ||||||
|  |     local original_buffer = curbufmeths.get_number() | ||||||
|  |     -- Place something in each of the buffers to make sure they stick around | ||||||
|  |     -- and set hidden so we can leave them | ||||||
|  |     command('set hidden') | ||||||
|  |     command('new') | ||||||
|  |     command('normal! ihello 2') | ||||||
|  |     command('new') | ||||||
|  |     command('normal! ihello 3') | ||||||
|  |  | ||||||
|  |     local final_buffer = curbufmeths.get_number() | ||||||
|  |  | ||||||
|  |     command('nnoremap <buffer> foo bar') | ||||||
|  |     -- Final buffer will have buffer mappings | ||||||
|  |     local buffer_table = local_copy(foo_bar_map_table) | ||||||
|  |     buffer_table['buffer'] = final_buffer | ||||||
|  |     eq({buffer_table}, meths.buf_get_keymap(final_buffer, 'n')) | ||||||
|  |     eq({buffer_table}, meths.buf_get_keymap(0, 'n')) | ||||||
|  |  | ||||||
|  |     command('buffer ' .. original_buffer) | ||||||
|  |     eq(original_buffer, curbufmeths.get_number()) | ||||||
|  |     -- Original buffer won't have any mappings | ||||||
|  |     eq({}, meths.get_keymap('n')) | ||||||
|  |     eq({}, curbufmeths.get_keymap('n')) | ||||||
|  |     eq({buffer_table}, meths.buf_get_keymap(final_buffer, 'n')) | ||||||
|  |   end) | ||||||
|  |  | ||||||
|  |   -- Test toggle switches for basic options | ||||||
|  |   -- @param  option  The key represented in the `maparg()` result dict | ||||||
|  |   local function global_and_buffer_test(map, | ||||||
|  |                                         option, | ||||||
|  |                                         option_token, | ||||||
|  |                                         global_on_result, | ||||||
|  |                                         buffer_on_result, | ||||||
|  |                                         global_off_result, | ||||||
|  |                                         buffer_off_result, | ||||||
|  |                                         new_windows) | ||||||
|  |  | ||||||
|  |     local function make_new_windows(number_of_windows) | ||||||
|  |       if new_windows == nil then | ||||||
|  |         return nil | ||||||
|  |       end | ||||||
|  |  | ||||||
|  |       for _=1,number_of_windows do | ||||||
|  |         command('new') | ||||||
|  |       end | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     local mode = string.sub(map, 1,1) | ||||||
|  |     -- Don't run this for the <buffer> mapping, since it doesn't make sense | ||||||
|  |     if option_token ~= '<buffer>' then | ||||||
|  |       it(string.format( 'returns %d for the key "%s" when %s is used globally with %s (%s)', | ||||||
|  |           global_on_result, option, option_token, map, mode), function() | ||||||
|  |         make_new_windows(new_windows) | ||||||
|  |         command(map .. ' ' .. option_token .. ' foo bar') | ||||||
|  |         local result = meths.get_keymap(mode)[1][option] | ||||||
|  |         eq(global_on_result, result) | ||||||
|  |       end) | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     it(string.format('returns %d for the key "%s" when %s is used for buffers with %s (%s)', | ||||||
|  |         buffer_on_result, option, option_token, map, mode), function() | ||||||
|  |       make_new_windows(new_windows) | ||||||
|  |       command(map .. ' <buffer> ' .. option_token .. ' foo bar') | ||||||
|  |       local result = curbufmeths.get_keymap(mode)[1][option] | ||||||
|  |       eq(buffer_on_result, result) | ||||||
|  |     end) | ||||||
|  |  | ||||||
|  |     -- Don't run these for the <buffer> mapping, since it doesn't make sense | ||||||
|  |     if option_token ~= '<buffer>' then | ||||||
|  |       it(string.format('returns %d for the key "%s" when %s is not used globally with %s (%s)', | ||||||
|  |           global_off_result, option, option_token, map, mode), function() | ||||||
|  |         make_new_windows(new_windows) | ||||||
|  |         command(map .. ' baz bat') | ||||||
|  |         local result = meths.get_keymap(mode)[1][option] | ||||||
|  |         eq(global_off_result, result) | ||||||
|  |       end) | ||||||
|  |  | ||||||
|  |       it(string.format('returns %d for the key "%s" when %s is not used for buffers with %s (%s)', | ||||||
|  |           buffer_off_result, option, option_token, map, mode), function() | ||||||
|  |         make_new_windows(new_windows) | ||||||
|  |         command(map .. ' <buffer> foo bar') | ||||||
|  |  | ||||||
|  |         local result = curbufmeths.get_keymap(mode)[1][option] | ||||||
|  |         eq(buffer_off_result, result) | ||||||
|  |       end) | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  |  | ||||||
|  |   -- Standard modes and returns the same values in the dictionary as maparg() | ||||||
|  |   local mode_list = {'nnoremap', 'nmap', 'imap', 'inoremap', 'cnoremap'} | ||||||
|  |   for mode in pairs(mode_list) do | ||||||
|  |     global_and_buffer_test(mode_list[mode], 'silent', '<silent>', 1, 1, 0, 0) | ||||||
|  |     global_and_buffer_test(mode_list[mode], 'nowait', '<nowait>', 1, 1, 0, 0) | ||||||
|  |     global_and_buffer_test(mode_list[mode], 'expr', '<expr>', 1, 1, 0, 0) | ||||||
|  |   end | ||||||
|  |  | ||||||
|  |   -- noremap will now be 2 if script was used, which is not the same as maparg() | ||||||
|  |   global_and_buffer_test('nmap', 'noremap', '<script>', 2, 2, 0, 0) | ||||||
|  |   global_and_buffer_test('nnoremap', 'noremap', '<script>', 2, 2, 1, 1) | ||||||
|  |  | ||||||
|  |   -- buffer will return the buffer ID, which is not the same as maparg() | ||||||
|  |   -- Three of these tests won't run | ||||||
|  |   global_and_buffer_test('nnoremap', 'buffer', '<buffer>', nil, 3, nil, nil, 2) | ||||||
|  |  | ||||||
|  |   it('returns script numbers for global maps', function() | ||||||
|  |     source([[ | ||||||
|  |       function! s:maparg_test_function() abort | ||||||
|  |         return 'testing' | ||||||
|  |       endfunction | ||||||
|  |  | ||||||
|  |       nnoremap fizz :call <SID>maparg_test_function()<CR> | ||||||
|  |     ]]) | ||||||
|  |     local sid_result = meths.get_keymap('n')[1]['sid'] | ||||||
|  |     eq(1, sid_result) | ||||||
|  |     eq('testing', meths.call_function('<SNR>' .. sid_result .. '_maparg_test_function', {})) | ||||||
|  |   end) | ||||||
|  |  | ||||||
|  |   it('returns script numbers for buffer maps', function() | ||||||
|  |     source([[ | ||||||
|  |       function! s:maparg_test_function() abort | ||||||
|  |         return 'testing' | ||||||
|  |       endfunction | ||||||
|  |  | ||||||
|  |       nnoremap <buffer> fizz :call <SID>maparg_test_function()<CR> | ||||||
|  |     ]]) | ||||||
|  |     local sid_result = curbufmeths.get_keymap('n')[1]['sid'] | ||||||
|  |     eq(1, sid_result) | ||||||
|  |     eq('testing', meths.call_function('<SNR>' .. sid_result .. '_maparg_test_function', {})) | ||||||
|  |   end) | ||||||
|  |  | ||||||
|  |   it('works with <F12> and others', function() | ||||||
|  |     command('nnoremap <F12> :let g:maparg_test_var = 1<CR>') | ||||||
|  |     eq('<F12>', meths.get_keymap('n')[1]['lhs']) | ||||||
|  |     eq(':let g:maparg_test_var = 1<CR>', meths.get_keymap('n')[1]['rhs']) | ||||||
|  |   end) | ||||||
|  | end) | ||||||
							
								
								
									
										120
									
								
								test/functional/eval/map_functions_spec.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										120
									
								
								test/functional/eval/map_functions_spec.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,120 @@ | |||||||
|  |  | ||||||
|  | local helpers = require('test.functional.helpers')(after_each) | ||||||
|  | local clear = helpers.clear | ||||||
|  | local eq = helpers.eq | ||||||
|  | local eval = helpers.eval | ||||||
|  | local funcs = helpers.funcs | ||||||
|  | local nvim = helpers.nvim | ||||||
|  | local source = helpers.source | ||||||
|  |  | ||||||
|  | describe('maparg()', function() | ||||||
|  |   before_each(clear) | ||||||
|  |  | ||||||
|  |   local foo_bar_map_table = { | ||||||
|  |       lhs='foo', | ||||||
|  |       silent=0, | ||||||
|  |       rhs='bar', | ||||||
|  |       expr=0, | ||||||
|  |       sid=0, | ||||||
|  |       buffer=0, | ||||||
|  |       nowait=0, | ||||||
|  |       mode='n', | ||||||
|  |       noremap=1, | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |   it('returns a dictionary', function() | ||||||
|  |     nvim('command', 'nnoremap foo bar') | ||||||
|  |     eq('bar', funcs.maparg('foo')) | ||||||
|  |     eq(foo_bar_map_table, funcs.maparg('foo', 'n', false, true)) | ||||||
|  |   end) | ||||||
|  |  | ||||||
|  |   it('returns 1 for silent when <silent> is used', function() | ||||||
|  |     nvim('command', 'nnoremap <silent> foo bar') | ||||||
|  |     eq(1, funcs.maparg('foo', 'n', false, true)['silent']) | ||||||
|  |  | ||||||
|  |     nvim('command', 'nnoremap baz bat') | ||||||
|  |     eq(0, funcs.maparg('baz', 'n', false, true)['silent']) | ||||||
|  |   end) | ||||||
|  |  | ||||||
|  |   it('returns an empty string when no map is present', function() | ||||||
|  |     eq('', funcs.maparg('not a mapping')) | ||||||
|  |   end) | ||||||
|  |  | ||||||
|  |   it('returns an empty dictionary when no map is present and dict is requested', function() | ||||||
|  |     eq({}, funcs.maparg('not a mapping', 'n', false, true)) | ||||||
|  |   end) | ||||||
|  |  | ||||||
|  |   it('returns the same value for noremap and <script>', function() | ||||||
|  |     nvim('command', 'inoremap <script> hello world') | ||||||
|  |     nvim('command', 'inoremap this that') | ||||||
|  |     eq( | ||||||
|  |       funcs.maparg('hello', 'i', false, true)['noremap'], | ||||||
|  |       funcs.maparg('this', 'i', false, true)['noremap'] | ||||||
|  |       ) | ||||||
|  |   end) | ||||||
|  |  | ||||||
|  |   it('returns a boolean for buffer', function() | ||||||
|  |     -- Open enough windows to know we aren't on buffer number 1 | ||||||
|  |     nvim('command', 'new') | ||||||
|  |     nvim('command', 'new') | ||||||
|  |     nvim('command', 'new') | ||||||
|  |     nvim('command', 'cnoremap <buffer> this that') | ||||||
|  |     eq(1, funcs.maparg('this', 'c', false, true)['buffer']) | ||||||
|  |  | ||||||
|  |     -- Global will return 0 always | ||||||
|  |     nvim('command', 'nnoremap other another') | ||||||
|  |     eq(0, funcs.maparg('other', 'n', false, true)['buffer']) | ||||||
|  |   end) | ||||||
|  |  | ||||||
|  |   it('returns script numbers', function() | ||||||
|  |     source([[ | ||||||
|  |       function! s:maparg_test_function() abort | ||||||
|  |         return 'testing' | ||||||
|  |       endfunction | ||||||
|  |  | ||||||
|  |       nnoremap fizz :call <SID>maparg_test_function()<CR> | ||||||
|  |     ]]) | ||||||
|  |     eq(1, funcs.maparg('fizz', 'n', false, true)['sid']) | ||||||
|  |     eq('testing', nvim('call_function', '<SNR>1_maparg_test_function', {})) | ||||||
|  |   end) | ||||||
|  |  | ||||||
|  |   it('works with <F12> and others', function() | ||||||
|  |     source([[ | ||||||
|  |       let g:maparg_test_var = 0 | ||||||
|  |  | ||||||
|  |       nnoremap <F12> :let g:maparg_test_var = 1<CR> | ||||||
|  |     ]]) | ||||||
|  |     eq(0, eval('g:maparg_test_var')) | ||||||
|  |     source([[ | ||||||
|  |       call feedkeys("\<F12>") | ||||||
|  |     ]]) | ||||||
|  |     eq(1, eval('g:maparg_test_var')) | ||||||
|  |  | ||||||
|  |     eq(':let g:maparg_test_var = 1<CR>', funcs.maparg('<F12>', 'n', false, true)['rhs']) | ||||||
|  |   end) | ||||||
|  |  | ||||||
|  |   it('works with <expr>', function() | ||||||
|  |     source([[ | ||||||
|  |       let counter = 0 | ||||||
|  |       inoremap <expr> <C-L> ListItem() | ||||||
|  |       inoremap <expr> <C-R> ListReset() | ||||||
|  |  | ||||||
|  |       func ListItem() | ||||||
|  |         let g:counter += 1 | ||||||
|  |         return g:counter . '. ' | ||||||
|  |       endfunc | ||||||
|  |  | ||||||
|  |       func ListReset() | ||||||
|  |         let g:counter = 0 | ||||||
|  |         return '' | ||||||
|  |       endfunc | ||||||
|  |  | ||||||
|  |       call feedkeys("i\<C-L>") | ||||||
|  |     ]]) | ||||||
|  |     eq(1, eval('g:counter')) | ||||||
|  |  | ||||||
|  |     local map_dict = funcs.maparg('<C-L>', 'i', false, true) | ||||||
|  |     eq(1, map_dict['expr']) | ||||||
|  |     eq('i', map_dict['mode']) | ||||||
|  |   end) | ||||||
|  | end) | ||||||
		Reference in New Issue
	
	Block a user
	 TJ DeVries
					TJ DeVries