get_keymap API (#6236)

* Add api function get keymap

nvim_get_keymap(mode)
nvim_buf_get_keymap(buffer, mode)
This commit is contained in:
TJ DeVries
2017-05-25 05:41:53 -05:00
committed by Björn Linse
parent f4fddbfb77
commit 45626de63f
8 changed files with 502 additions and 23 deletions

View File

@@ -453,6 +453,26 @@ Integer nvim_buf_get_changedtick(Buffer buffer, Error *err)
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
///
/// @param buffer Buffer handle

View File

@@ -24,6 +24,7 @@
#include "nvim/option_defs.h"
#include "nvim/version.h"
#include "nvim/lib/kvec.h"
#include "nvim/getchar.h"
/// Helper structure for vim_to_object
typedef struct {
@@ -1034,3 +1035,41 @@ void api_set_error(Error *err, ErrorType errType, const char *format, ...)
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;
}

View File

@@ -742,6 +742,17 @@ Dictionary nvim_get_mode(void)
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)
FUNC_API_SINCE(1) FUNC_API_ASYNC FUNC_API_REMOTE_ONLY
{

View File

@@ -438,6 +438,9 @@ typedef TV_DICTITEM_STRUCT(sizeof("changedtick")) ChangedtickDictItem;
#define BUF_HAS_QF_ENTRY 1
#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
*
@@ -526,8 +529,8 @@ struct file_buffer {
*/
uint64_t b_chartab[4];
/* Table used for mappings local to a buffer. */
mapblock_T *(b_maphash[256]);
// Table used for mappings local to a buffer.
mapblock_T *(b_maphash[MAX_MAPHASH]);
/* First abbreviation local to a buffer. */
mapblock_T *b_first_abbr;

View File

@@ -12102,22 +12102,7 @@ static void get_maparg(typval_T *argvars, typval_T *rettv, int exact)
tv_dict_alloc_ret(rettv);
if (rhs != NULL) {
// Return a dictionary.
char_u *lhs = str2special_save(mp->m_keys, 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);
mapblock_fill_dict(rettv->vval.v_dict, mp, buffer_local, true);
}
}
}
@@ -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);
}
/// 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
*/

View File

@@ -18,6 +18,7 @@
#include "nvim/vim.h"
#include "nvim/ascii.h"
#include "nvim/getchar.h"
#include "nvim/buffer_defs.h"
#include "nvim/charset.h"
#include "nvim/cursor.h"
#include "nvim/edit.h"
@@ -47,6 +48,7 @@
#include "nvim/event/loop.h"
#include "nvim/os/input.h"
#include "nvim/os/os.h"
#include "nvim/api/private/handle.h"
/*
* These buffers are used for storing:
@@ -102,11 +104,10 @@ static int block_redo = FALSE;
(NORMAL + VISUAL + SELECTMODE + \
OP_PENDING)) ? (c1) : ((c1) ^ 0x80))
/*
* Each mapping is put in one of the 256 hash lists, to speed up finding it.
*/
static mapblock_T *(maphash[256]);
static int maphash_valid = FALSE;
// Each mapping is put in one of the MAX_MAPHASH hash lists,
// to speed up finding it.
static mapblock_T *(maphash[MAX_MAPHASH]);
static bool maphash_valid = false;
/*
* List used for abbreviations.
@@ -4237,3 +4238,17 @@ static bool typebuf_match_len(const uint8_t *str, int *mlen)
*mlen = i;
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];
}