refactor: adopt termkey and eliminate duplicate code

Termkey is abandoned and it's now our code, so there's no reason not to
treat it as such. An alternative approach could be to have a proper repo
that we maintain such as with unibilium, although with this approach we
can make a few assumptions that will allow us to remove more code.

Also eliminate duplicate code from both termkey and libvterm.
This commit is contained in:
dundargoc 2024-08-14 15:52:51 +02:00 committed by dundargoc
parent 975aeee537
commit f9108378b7
20 changed files with 2159 additions and 2592 deletions

View File

@ -160,7 +160,6 @@ These dependencies are "vendored" (inlined), we must update the sources manually
* Needs to be updated when LPeg is updated.
* `src/bit.c`: only for PUC lua: port of `require'bit'` from luajit https://bitop.luajit.org/
* `runtime/lua/coxpcall.lua`: coxpcall (only needed for PUC lua, builtin to luajit)
* `src/termkey`: [libtermkey](https://github.com/neovim/libtermkey)
Other dependencies
--------------------------

View File

@ -54,8 +54,6 @@ if(ENABLE_WASMTIME)
target_compile_definitions(nvim_bin PRIVATE HAVE_WASMTIME)
endif()
target_compile_definitions(main_lib INTERFACE HAVE_UNIBILIUM)
# The unit test lib requires LuaJIT; it will be skipped if LuaJIT is missing.
option(PREFER_LUA "Prefer Lua over LuaJIT in the nvim executable." OFF)
if(PREFER_LUA)
@ -153,7 +151,7 @@ if(UNIX)
endif()
if(CMAKE_SYSTEM_NAME MATCHES "Windows")
target_compile_definitions(main_lib INTERFACE _WIN32_WINNT=0x0602 MSWIN)
target_compile_definitions(main_lib INTERFACE _WIN32_WINNT=0x0602 MSWIN WIN32_LEAN_AND_MEAN)
target_link_libraries(main_lib INTERFACE netapi32)
elseif(CMAKE_SYSTEM_NAME MATCHES "Darwin")
target_link_libraries(nvim_bin PRIVATE "-framework CoreServices")
@ -366,8 +364,8 @@ file(MAKE_DIRECTORY ${TOUCHES_DIR} ${GENERATED_DIR} ${GENERATED_INCLUDES_DIR})
file(GLOB NVIM_SOURCES CONFIGURE_DEPENDS *.c)
file(GLOB NVIM_HEADERS CONFIGURE_DEPENDS *.h)
file(GLOB EXTERNAL_SOURCES CONFIGURE_DEPENDS ../xdiff/*.c ../mpack/*.c ../cjson/*.c ../klib/*.c ../termkey/*.c ../vterm/*.c)
file(GLOB EXTERNAL_HEADERS CONFIGURE_DEPENDS ../xdiff/*.h ../mpack/*.h ../cjson/*.h ../klib/*.h ../termkey/*.h ../vterm/*.h)
file(GLOB EXTERNAL_SOURCES CONFIGURE_DEPENDS ../xdiff/*.c ../mpack/*.c ../cjson/*.c ../klib/*.c ../vterm/*.c)
file(GLOB EXTERNAL_HEADERS CONFIGURE_DEPENDS ../xdiff/*.h ../mpack/*.h ../cjson/*.h ../klib/*.h ../vterm/*.h)
file(GLOB NLUA0_SOURCES CONFIGURE_DEPENDS ../mpack/*.c)
@ -378,6 +376,15 @@ if(PREFER_LUA)
target_compile_definitions(main_lib INTERFACE NVIM_VENDOR_BIT)
endif()
# Inlined external projects, we don't maintain it. #9306
if(MSVC)
set_source_files_properties(
${EXTERNAL_SOURCES} PROPERTIES COMPILE_OPTIONS "-wd4090;-wd4244;-wd4267")
else()
set_source_files_properties(
${EXTERNAL_SOURCES} PROPERTIES COMPILE_OPTIONS "-Wno-conversion;-Wno-missing-noreturn;-Wno-missing-format-attribute;-Wno-double-promotion;-Wno-strict-prototypes;-Wno-misleading-indentation;-Wno-sign-compare;-Wno-implicit-fallthrough;-Wno-missing-prototypes;-Wno-missing-field-initializers")
endif()
list(APPEND NLUA0_SOURCES ${PROJECT_SOURCE_DIR}/src/nlua0.c)
foreach(subdir
@ -386,6 +393,7 @@ foreach(subdir
api/private
msgpack_rpc
tui
tui/termkey
event
eval
lua
@ -407,49 +415,36 @@ endforeach()
list(SORT NVIM_SOURCES)
list(SORT NVIM_HEADERS)
list(APPEND LINT_NVIM_SOURCES ${NVIM_SOURCES} ${NVIM_HEADERS})
foreach(sfile ${NVIM_SOURCES})
get_filename_component(f ${sfile} NAME)
if(WIN32 AND ${f} MATCHES "^(pty_process_unix.c)$")
list(APPEND to_remove ${sfile})
list(REMOVE_ITEM NVIM_SOURCES ${sfile})
endif()
if(NOT WIN32 AND ${f} MATCHES "^(pty_process_win.c)$")
list(APPEND to_remove ${sfile})
list(REMOVE_ITEM NVIM_SOURCES ${sfile})
endif()
if(NOT WIN32 AND ${f} MATCHES "^(pty_conpty_win.c)$")
list(APPEND to_remove ${sfile})
list(REMOVE_ITEM NVIM_SOURCES ${sfile})
endif()
if(NOT WIN32 AND ${f} MATCHES "^(os_win_console.c)$")
list(APPEND to_remove ${sfile})
list(REMOVE_ITEM NVIM_SOURCES ${sfile})
endif()
endforeach()
list(REMOVE_ITEM NVIM_SOURCES ${to_remove})
foreach(hfile ${NVIM_HEADERS})
get_filename_component(f ${hfile} NAME)
if(WIN32 AND ${f} MATCHES "^(unix_defs.h)$")
list(APPEND to_remove_h ${hfile})
list(REMOVE_ITEM NVIM_HEADERS ${hfile})
endif()
if(WIN32 AND ${f} MATCHES "^(pty_process_unix.h)$")
list(APPEND to_remove_h ${hfile})
list(REMOVE_ITEM NVIM_HEADERS ${hfile})
endif()
if(NOT WIN32 AND ${f} MATCHES "^(win_defs.h)$")
list(APPEND to_remove_h ${hfile})
list(REMOVE_ITEM NVIM_HEADERS ${hfile})
endif()
endforeach()
list(REMOVE_ITEM NVIM_HEADERS ${to_remove_h})
# xdiff, mpack, lua-cjson, termkey: inlined external project, we don't maintain it. #9306
if(MSVC)
set_source_files_properties(
${EXTERNAL_SOURCES} PROPERTIES COMPILE_OPTIONS "-wd4090;-wd4244;-wd4267")
else()
set_source_files_properties(
${EXTERNAL_SOURCES} PROPERTIES COMPILE_OPTIONS "-Wno-conversion;-Wno-missing-noreturn;-Wno-missing-format-attribute;-Wno-double-promotion;-Wno-strict-prototypes;-Wno-misleading-indentation;-Wno-sign-compare;-Wno-implicit-fallthrough;-Wno-missing-prototypes;-Wno-missing-field-initializers")
endif()
list(APPEND LINT_NVIM_SOURCES ${NVIM_SOURCES} ${NVIM_HEADERS})
# Log level (NVIM_LOG_DEBUG in log.h)
if(CI_BUILD)
@ -849,7 +844,7 @@ endif()
add_glob_target(
TARGET lintc-clang-tidy
COMMAND ${CLANG_TIDY_PRG}
FILES ${NVIM_SOURCES} ${NVIM_HEADERS}
FILES ${LINT_NVIM_SOURCES}
FLAGS --quiet
EXCLUDE ${EXCLUDE_CLANG_TIDY})
@ -862,7 +857,7 @@ endif()
add_glob_target(
TARGET clang-analyzer
COMMAND ${CLANG_TIDY_PRG}
FILES ${NVIM_SOURCES} ${NVIM_HEADERS}
FILES ${LINT_NVIM_SOURCES}
FLAGS --quiet
--checks='
-*,
@ -905,13 +900,13 @@ add_glob_target(
TARGET lintc-uncrustify
COMMAND ${UNCRUSTIFY_PRG}
FLAGS -c ${UNCRUSTIFY_CONFIG} -q --check
FILES ${LINT_NVIM_SOURCES})
FILES ${NVIM_SOURCES} ${NVIM_HEADERS})
add_glob_target(
TARGET formatc
COMMAND ${UNCRUSTIFY_PRG}
FLAGS -c ${UNCRUSTIFY_CONFIG} --replace --no-backup
FILES ${LINT_NVIM_SOURCES})
FILES ${NVIM_SOURCES} ${NVIM_HEADERS})
add_dependencies(lintc-uncrustify uncrustify_update_config)
add_dependencies(formatc uncrustify_update_config)

View File

@ -16,9 +16,6 @@
#include <sys/stat.h>
#include <windows.h>
// vterm.h defines an `unsigned int small` in a struct, triggering error C2632
#undef small
// Windows does not have S_IFLNK but libuv defines it
// and sets the flag for us when calling uv_fs_stat.
#include <uv.h>

View File

@ -7,24 +7,27 @@
#include "nvim/api/private/defs.h"
#include "nvim/api/private/helpers.h"
#include "nvim/event/loop.h"
#include "nvim/event/rstream.h"
#include "nvim/event/stream.h"
#include "nvim/macros_defs.h"
#include "nvim/main.h"
#include "nvim/map_defs.h"
#include "nvim/memory.h"
#include "nvim/msgpack_rpc/channel.h"
#include "nvim/option_vars.h"
#include "nvim/os/os.h"
#include "nvim/os/os_defs.h"
#include "nvim/strings.h"
#include "nvim/tui/input.h"
#include "nvim/tui/input_defs.h"
#include "nvim/tui/termkey/driver-csi.h"
#include "nvim/tui/termkey/termkey.h"
#include "nvim/tui/tui.h"
#include "nvim/ui_client.h"
#ifdef MSWIN
# include "nvim/os/os_win_console.h"
#endif
#include "nvim/event/rstream.h"
#include "nvim/msgpack_rpc/channel.h"
#define READ_STREAM_SIZE 0xfff
@ -261,7 +264,7 @@ static size_t handle_more_modifiers(TermKeyKey *key, char *buf, size_t buflen)
static void handle_kitty_key_protocol(TermInput *input, TermKeyKey *key)
{
const char *name = pmap_get(int)(&kitty_key_map, (int)key->code.codepoint);
const char *name = pmap_get(int)(&kitty_key_map, key->code.codepoint);
if (name) {
char buf[64];
size_t len = 0;
@ -598,7 +601,7 @@ static void handle_unknown_csi(TermInput *input, const TermKeyKey *key)
// contain, so just allocate enough space for a large upper bound
TermKeyCsiParam params[16];
size_t nparams = 16;
unsigned long cmd;
unsigned cmd;
if (termkey_interpret_csi(input->tk, key, params, &nparams, &cmd) != TERMKEY_RES_KEY) {
return;
}
@ -641,7 +644,7 @@ static void handle_unknown_csi(TermInput *input, const TermKeyKey *key)
case 't':
if (nparams == 5) {
// We only care about the first 3 parameters, and we ignore subparameters
long args[3];
int args[3];
for (size_t i = 0; i < ARRAY_SIZE(args); i++) {
if (termkey_interpret_csi_param(params[i], &args[i], NULL, NULL) != TERMKEY_RES_KEY) {
return;
@ -650,8 +653,8 @@ static void handle_unknown_csi(TermInput *input, const TermKeyKey *key)
if (args[0] == 48) {
// In-band resize event (DEC private mode 2048)
int height_chars = (int)args[1];
int width_chars = (int)args[2];
int height_chars = args[1];
int width_chars = args[2];
tui_set_size(input->tui_data, width_chars, height_chars);
ui_client_set_size(width_chars, height_chars);
}

View File

@ -6,9 +6,9 @@
#include "nvim/event/defs.h"
#include "nvim/tui/input_defs.h" // IWYU pragma: keep
#include "nvim/tui/termkey/termkey_defs.h"
#include "nvim/tui/tui_defs.h"
#include "nvim/types_defs.h"
#include "termkey/termkey.h"
typedef enum {
kKeyEncodingLegacy, ///< Legacy key encoding

View File

@ -0,0 +1 @@
// Adapted from libtermkey: https://github.com/neovim/libtermkey

View File

@ -0,0 +1,7 @@
#pragma once
#include "nvim/tui/termkey/termkey_defs.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "tui/termkey/driver-csi.h.generated.h"
#endif

View File

@ -1,33 +1,28 @@
// we want strdup()
#define _XOPEN_SOURCE 600
#include "termkey.h"
#include "termkey-internal.h"
#ifdef HAVE_UNIBILIUM
# include <unibilium.h>
#else
# include <curses.h>
# include <term.h>
/* curses.h has just polluted our namespace. We want this back */
# undef buttons
#endif
#include <ctype.h>
#include <errno.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unibilium.h>
#include "nvim/memory.h"
#include "nvim/tui/termkey/driver-ti.h"
#include "nvim/tui/termkey/termkey-internal.h"
#include "nvim/tui/termkey/termkey.h"
#ifndef _WIN32
# include <unistd.h>
#else
# include <io.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
#define streq(a,b) (!strcmp(a,b))
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "tui/termkey/driver-ti.c.generated.h"
#endif
#define streq(a, b) (!strcmp(a, b))
#define MAX_FUNCNAME 9
@ -36,9 +31,8 @@ static struct {
TermKeyType type;
TermKeySym sym;
int mods;
} funcs[] =
{
/* THIS LIST MUST REMAIN SORTED! */
} funcs[] = {
// THIS LIST MUST REMAIN SORTED!
{ "backspace", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_BACKSPACE, 0 },
{ "begin", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_BEGIN, 0 },
{ "beg", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_BEGIN, 0 },
@ -61,12 +55,12 @@ static struct {
{ "mark", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_MARK, 0 },
{ "message", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_MESSAGE, 0 },
{ "move", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_MOVE, 0 },
{ "next", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_PAGEDOWN, 0 }, // Not quite, but it's the best we can do
{ "next", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_PAGEDOWN, 0 }, // Not quite, but it's the best we can do
{ "npage", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_PAGEDOWN, 0 },
{ "open", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_OPEN, 0 },
{ "options", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_OPTIONS, 0 },
{ "ppage", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_PAGEUP, 0 },
{ "previous", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_PAGEUP, 0 }, // Not quite, but it's the best we can do
{ "previous", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_PAGEUP, 0 }, // Not quite, but it's the best we can do
{ "print", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_PRINT, 0 },
{ "redo", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_REDO, 0 },
{ "reference", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_REFERENCE, 0 },
@ -80,34 +74,34 @@ static struct {
{ "suspend", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_SUSPEND, 0 },
{ "undo", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_UNDO, 0 },
{ "up", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_UP, 0 },
{ NULL },
{ NULL, 0, 0, 0 },
};
#ifdef HAVE_UNIBILIUM
static enum unibi_string unibi_lookup_str(const char *name)
{
for(enum unibi_string ret = unibi_string_begin_+1; ret < unibi_string_end_; ret++)
if(streq(unibi_name_str(ret), name))
for (enum unibi_string ret = unibi_string_begin_ + 1; ret < unibi_string_end_; ret++) {
if (streq(unibi_name_str(ret), name)) {
return ret;
}
}
return -1;
return (enum unibi_string)-1;
}
static const char *unibi_get_str_by_name(const unibi_term *ut, const char *name)
{
enum unibi_string idx = unibi_lookup_str(name);
if(idx == (enum unibi_string)-1)
if (idx == (enum unibi_string)-1) {
return NULL;
}
return unibi_get_str(ut, idx);
}
#endif
/* To be efficient at lookups, we store the byte sequence => keyinfo mapping
* in a trie. This avoids a slow linear search through a flat list of
* sequences. Because it is likely most nodes will be very sparse, we optimise
* vector to store an extent map after the database is loaded.
*/
// To be efficient at lookups, we store the byte sequence => keyinfo mapping
// in a trie. This avoids a slow linear search through a flat list of
// sequences. Because it is likely most nodes will be very sparse, we optimise
// vector to store an extent map after the database is loaded.
typedef enum {
TYPE_KEY,
@ -125,126 +119,110 @@ struct trie_node_key {
struct trie_node_arr {
trie_nodetype type;
unsigned char min, max; /* INCLUSIVE endpoints of the extent range */
struct trie_node *arr[]; /* dynamic size at allocation time */
unsigned char min, max; // INCLUSIVE endpoints of the extent range
struct trie_node *arr[]; // dynamic size at allocation time
};
typedef struct {
TermKey *tk;
#ifdef HAVE_UNIBILIUM
unibi_term *unibi; /* only valid until first 'start' call */
#else
char *term; /* only valid until first 'start' call */
#endif
struct trie_node *root;
char *start_string;
char *stop_string;
} TermKeyTI;
static int insert_seq(TermKeyTI *ti, const char *seq, struct trie_node *node);
static struct trie_node *new_node_key(TermKeyType type, TermKeySym sym, int modmask, int modset)
{
struct trie_node_key *n = malloc(sizeof(*n));
if(!n)
return NULL;
struct trie_node_key *n = xmalloc(sizeof(*n));
n->type = TYPE_KEY;
n->key.type = type;
n->key.sym = sym;
n->key.sym = sym;
n->key.modifier_mask = modmask;
n->key.modifier_set = modset;
n->key.modifier_set = modset;
return (struct trie_node*)n;
return (struct trie_node *)n;
}
static struct trie_node *new_node_arr(unsigned char min, unsigned char max)
{
struct trie_node_arr *n = malloc(sizeof(*n) + ((int)max-min+1) * sizeof(n->arr[0]));
if(!n)
return NULL;
struct trie_node_arr *n = xmalloc(sizeof(*n) + (max - min + 1) * sizeof(n->arr[0]));
n->type = TYPE_ARR;
n->min = min; n->max = max;
int i;
for(i = min; i <= max; i++)
n->arr[i-min] = NULL;
for (i = min; i <= max; i++) {
n->arr[i - min] = NULL;
}
return (struct trie_node*)n;
return (struct trie_node *)n;
}
static struct trie_node *lookup_next(struct trie_node *n, unsigned char b)
{
switch(n->type) {
switch (n->type) {
case TYPE_KEY:
fprintf(stderr, "ABORT: lookup_next within a TYPE_KEY node\n");
abort();
case TYPE_ARR:
{
struct trie_node_arr *nar = (struct trie_node_arr*)n;
if(b < nar->min || b > nar->max)
return NULL;
return nar->arr[b - nar->min];
case TYPE_ARR: {
struct trie_node_arr *nar = (struct trie_node_arr *)n;
if (b < nar->min || b > nar->max) {
return NULL;
}
return nar->arr[b - nar->min];
}
}
return NULL; // Never reached but keeps compiler happy
return NULL; // Never reached but keeps compiler happy
}
static void free_trie(struct trie_node *n)
{
switch(n->type) {
switch (n->type) {
case TYPE_KEY:
break;
case TYPE_ARR:
{
struct trie_node_arr *nar = (struct trie_node_arr*)n;
int i;
for(i = nar->min; i <= nar->max; i++)
if(nar->arr[i - nar->min])
free_trie(nar->arr[i - nar->min]);
break;
case TYPE_ARR: {
struct trie_node_arr *nar = (struct trie_node_arr *)n;
int i;
for (i = nar->min; i <= nar->max; i++) {
if (nar->arr[i - nar->min]) {
free_trie(nar->arr[i - nar->min]);
}
}
break;
}
}
free(n);
xfree(n);
}
static struct trie_node *compress_trie(struct trie_node *n)
{
if(!n)
if (!n) {
return NULL;
}
switch(n->type) {
switch (n->type) {
case TYPE_KEY:
return n;
case TYPE_ARR:
{
struct trie_node_arr *nar = (struct trie_node_arr*)n;
unsigned char min, max;
// Find the real bounds
for(min = 0; !nar->arr[min]; min++)
if(min == 255 && !nar->arr[min]) {
free(nar);
return new_node_arr(1, 0);
}
for(max = 0xff; !nar->arr[max]; max--)
;
struct trie_node_arr *new = (struct trie_node_arr*)new_node_arr(min, max);
int i;
for(i = min; i <= max; i++)
new->arr[i - min] = compress_trie(nar->arr[i]);
free(nar);
return (struct trie_node*)new;
case TYPE_ARR: {
struct trie_node_arr *nar = (struct trie_node_arr *)n;
unsigned char min, max;
// Find the real bounds
for (min = 0; !nar->arr[min]; min++) {
if (min == 255 && !nar->arr[min]) {
xfree(nar);
return new_node_arr(1, 0);
}
}
for (max = 0xff; !nar->arr[max]; max--) {}
struct trie_node_arr *new = (struct trie_node_arr *)new_node_arr(min, max);
int i;
for (i = min; i <= max; i++) {
new->arr[i - min] = compress_trie(nar->arr[i]);
}
xfree(nar);
return (struct trie_node *)new;
}
}
return n;
@ -254,21 +232,20 @@ static bool try_load_terminfo_key(TermKeyTI *ti, const char *name, struct keyinf
{
const char *value = NULL;
#ifdef HAVE_UNIBILIUM
if(ti->unibi)
if (ti->unibi) {
value = unibi_get_str_by_name(ti->unibi, name);
#else
if(ti->term)
value = tigetstr(name);
#endif
}
if(ti->tk->ti_getstr_hook)
if (ti->tk->ti_getstr_hook) {
value = (ti->tk->ti_getstr_hook)(name, value, ti->tk->ti_getstr_hook_data);
}
if(!value || value == (char*)-1 || !value[0])
if (!value || value == (char *)-1 || !value[0]) {
return false;
}
struct trie_node *node = new_node_key(info->type, info->sym, info->modifier_mask, info->modifier_set);
struct trie_node *node = new_node_key(info->type, info->sym, info->modifier_mask,
info->modifier_set);
insert_seq(ti, value, node);
return true;
@ -278,288 +255,257 @@ static int load_terminfo(TermKeyTI *ti)
{
int i;
#ifdef HAVE_UNIBILIUM
unibi_term *unibi = ti->unibi;
#else
{
int err;
/* Have to cast away the const. But it's OK - we know terminfo won't really
* modify term */
if(setupterm((char*)ti->term, 1, &err) != OK)
return 0;
}
#endif
ti->root = new_node_arr(0, 0xff);
if(!ti->root)
if (!ti->root) {
return 0;
}
/* First the regular key strings
*/
for(i = 0; funcs[i].funcname; i++) {
// First the regular key strings
for (i = 0; funcs[i].funcname; i++) {
char name[MAX_FUNCNAME + 5 + 1];
sprintf(name, "key_%s", funcs[i].funcname);
if(!try_load_terminfo_key(ti, name, &(struct keyinfo){
.type = funcs[i].type,
.sym = funcs[i].sym,
.modifier_mask = funcs[i].mods,
.modifier_set = funcs[i].mods,
}))
sprintf(name, "key_%s", funcs[i].funcname); // NOLINT(runtime/printf)
if (!try_load_terminfo_key(ti, name, &(struct keyinfo){
.type = funcs[i].type,
.sym = funcs[i].sym,
.modifier_mask = funcs[i].mods,
.modifier_set = funcs[i].mods,
})) {
continue;
}
/* Maybe it has a shifted version */
sprintf(name, "key_s%s", funcs[i].funcname);
// Maybe it has a shifted version
sprintf(name, "key_s%s", funcs[i].funcname); // NOLINT(runtime/printf)
try_load_terminfo_key(ti, name, &(struct keyinfo){
.type = funcs[i].type,
.sym = funcs[i].sym,
.modifier_mask = funcs[i].mods | TERMKEY_KEYMOD_SHIFT,
.modifier_set = funcs[i].mods | TERMKEY_KEYMOD_SHIFT,
.type = funcs[i].type,
.sym = funcs[i].sym,
.modifier_mask = funcs[i].mods | TERMKEY_KEYMOD_SHIFT,
.modifier_set = funcs[i].mods | TERMKEY_KEYMOD_SHIFT,
});
}
/* Now the F<digit> keys
*/
for(i = 1; i < 255; i++) {
// Now the F<digit> keys
for (i = 1; i < 255; i++) {
char name[9];
sprintf(name, "key_f%d", i);
if(!try_load_terminfo_key(ti, name, &(struct keyinfo){
.type = TERMKEY_TYPE_FUNCTION,
.sym = i,
.modifier_mask = 0,
.modifier_set = 0,
}))
sprintf(name, "key_f%d", i); // NOLINT(runtime/printf)
if (!try_load_terminfo_key(ti, name, &(struct keyinfo){
.type = TERMKEY_TYPE_FUNCTION,
.sym = i,
.modifier_mask = 0,
.modifier_set = 0,
})) {
break;
}
}
/* Finally mouse mode */
// Finally mouse mode
{
const char *value = NULL;
#ifdef HAVE_UNIBILIUM
if(ti->unibi)
if (ti->unibi) {
value = unibi_get_str_by_name(ti->unibi, "key_mouse");
#else
if(ti->term)
value = tigetstr("key_mouse");
#endif
}
if(ti->tk->ti_getstr_hook)
if (ti->tk->ti_getstr_hook) {
value = (ti->tk->ti_getstr_hook)("key_mouse", value, ti->tk->ti_getstr_hook_data);
}
/* Some terminfos (e.g. xterm-1006) claim a different key_mouse that won't
* give X10 encoding. We'll only accept this if it's exactly "\e[M"
*/
if(value && streq(value, "\x1b[M")) {
// Some terminfos (e.g. xterm-1006) claim a different key_mouse that won't
// give X10 encoding. We'll only accept this if it's exactly "\e[M"
if (value && streq(value, "\x1b[M")) {
struct trie_node *node = new_node_key(TERMKEY_TYPE_MOUSE, 0, 0, 0);
insert_seq(ti, value, node);
}
}
/* Take copies of these terminfo strings, in case we build multiple termkey
* instances for multiple different termtypes, and it's different by the
* time we want to use it
*/
#ifdef HAVE_UNIBILIUM
const char *keypad_xmit = unibi ?
unibi_get_str(unibi, unibi_keypad_xmit) :
NULL;
#endif
// Take copies of these terminfo strings, in case we build multiple termkey
// instances for multiple different termtypes, and it's different by the
// time we want to use it
const char *keypad_xmit = unibi
? unibi_get_str(unibi, unibi_keypad_xmit)
: NULL;
if(keypad_xmit)
ti->start_string = strdup(keypad_xmit);
else
if (keypad_xmit) {
ti->start_string = xstrdup(keypad_xmit);
} else {
ti->start_string = NULL;
}
#ifdef HAVE_UNIBILIUM
const char *keypad_local = unibi ?
unibi_get_str(unibi, unibi_keypad_local) :
NULL;
#endif
const char *keypad_local = unibi
? unibi_get_str(unibi, unibi_keypad_local)
: NULL;
if(keypad_local)
ti->stop_string = strdup(keypad_local);
else
if (keypad_local) {
ti->stop_string = xstrdup(keypad_local);
} else {
ti->stop_string = NULL;
}
#ifdef HAVE_UNIBILIUM
if(unibi)
if (unibi) {
unibi_destroy(unibi);
}
ti->unibi = NULL;
#else
if(ti->term)
free(ti->term);
ti->term = NULL;
#endif
ti->root = compress_trie(ti->root);
return 1;
}
static void *new_driver(TermKey *tk, const char *term)
void *new_driver_ti(TermKey *tk, const char *term)
{
TermKeyTI *ti = malloc(sizeof *ti);
if(!ti)
return NULL;
TermKeyTI *ti = xmalloc(sizeof *ti);
ti->tk = tk;
ti->root = NULL;
ti->start_string = NULL;
ti->stop_string = NULL;
#ifdef HAVE_UNIBILIUM
ti->unibi = unibi_from_term(term);
int saved_errno = errno;
if(!ti->unibi && saved_errno != ENOENT) {
free(ti);
if (!ti->unibi && saved_errno != ENOENT) {
xfree(ti);
return NULL;
}
/* ti->unibi may be NULL if errno == ENOENT. That means the terminal wasn't
* known. Lets keep going because if we get getstr hook that might invent
* new strings for us
*/
#else
{
int err;
ti->term = NULL;
/* Have to cast away the const. But it's OK - we know terminfo won't really
* modify term */
if(setupterm((char*)term, 1, &err) == OK)
ti->term = strdup(term);
}
#endif
// ti->unibi may be NULL if errno == ENOENT. That means the terminal wasn't
// known. Lets keep going because if we get getstr hook that might invent
// new strings for us
return ti;
}
static int start_driver(TermKey *tk, void *info)
int start_driver_ti(TermKey *tk, void *info)
{
TermKeyTI *ti = info;
struct stat statbuf;
char *start_string;
size_t len;
if(!ti->root)
if (!ti->root) {
load_terminfo(ti);
}
start_string = ti->start_string;
if(tk->fd == -1 || !start_string)
if (tk->fd == -1 || !start_string) {
return 1;
}
/* The terminfo database will contain keys in application cursor key mode.
* We may need to enable that mode
*/
// The terminfo database will contain keys in application cursor key mode.
// We may need to enable that mode
/* There's no point trying to write() to a pipe */
if(fstat(tk->fd, &statbuf) == -1)
// There's no point trying to write() to a pipe
if (fstat(tk->fd, &statbuf) == -1) {
return 0;
}
#ifndef _WIN32
if(S_ISFIFO(statbuf.st_mode))
if (S_ISFIFO(statbuf.st_mode)) {
return 1;
}
#endif
// Can't call putp or tputs because they suck and don't give us fd control
len = strlen(start_string);
while(len) {
size_t written = write(tk->fd, start_string, len);
if(written == -1)
while (len) {
size_t written = (size_t)write(tk->fd, start_string, (unsigned)len);
if (written == (size_t)-1) {
return 0;
}
start_string += written;
len -= written;
}
return 1;
}
static int stop_driver(TermKey *tk, void *info)
int stop_driver_ti(TermKey *tk, void *info)
{
TermKeyTI *ti = info;
struct stat statbuf;
char *stop_string = ti->stop_string;
size_t len;
if(tk->fd == -1 || !stop_string)
if (tk->fd == -1 || !stop_string) {
return 1;
}
/* There's no point trying to write() to a pipe */
if(fstat(tk->fd, &statbuf) == -1)
// There's no point trying to write() to a pipe
if (fstat(tk->fd, &statbuf) == -1) {
return 0;
}
#ifndef _WIN32
if(S_ISFIFO(statbuf.st_mode))
if (S_ISFIFO(statbuf.st_mode)) {
return 1;
}
#endif
/* The terminfo database will contain keys in application cursor key mode.
* We may need to enable that mode
*/
// The terminfo database will contain keys in application cursor key mode.
// We may need to enable that mode
// Can't call putp or tputs because they suck and don't give us fd control
len = strlen(stop_string);
while(len) {
size_t written = write(tk->fd, stop_string, len);
if(written == -1)
while (len) {
size_t written = (size_t)write(tk->fd, stop_string, (unsigned)len);
if (written == (size_t)-1) {
return 0;
}
stop_string += written;
len -= written;
}
return 1;
}
static void free_driver(void *info)
void free_driver_ti(void *info)
{
TermKeyTI *ti = info;
free_trie(ti->root);
if(ti->start_string)
free(ti->start_string);
if (ti->start_string) {
xfree(ti->start_string);
}
if(ti->stop_string)
free(ti->stop_string);
if (ti->stop_string) {
xfree(ti->stop_string);
}
#ifdef HAVE_UNIBILIUM
if(ti->unibi)
if (ti->unibi) {
unibi_destroy(ti->unibi);
#else
if(ti->term)
free(ti->term);
#endif
}
free(ti);
xfree(ti);
}
#define CHARAT(i) (tk->buffer[tk->buffstart + (i)])
static TermKeyResult peekkey(TermKey *tk, void *info, TermKeyKey *key, int force, size_t *nbytep)
TermKeyResult peekkey_ti(TermKey *tk, void *info, TermKeyKey *key, int force, size_t *nbytep)
{
TermKeyTI *ti = info;
if(tk->buffcount == 0)
if (tk->buffcount == 0) {
return tk->is_closed ? TERMKEY_RES_EOF : TERMKEY_RES_NONE;
}
struct trie_node *p = ti->root;
unsigned int pos = 0;
while(pos < tk->buffcount) {
unsigned pos = 0;
while (pos < tk->buffcount) {
p = lookup_next(p, CHARAT(pos));
if(!p)
if (!p) {
break;
}
pos++;
if(p->type != TYPE_KEY)
if (p->type != TYPE_KEY) {
continue;
}
struct trie_node_key *nk = (struct trie_node_key*)p;
if(nk->key.type == TERMKEY_TYPE_MOUSE) {
struct trie_node_key *nk = (struct trie_node_key *)p;
if (nk->key.type == TERMKEY_TYPE_MOUSE) {
tk->buffstart += pos;
tk->buffcount -= pos;
@ -568,14 +514,15 @@ static TermKeyResult peekkey(TermKey *tk, void *info, TermKeyKey *key, int force
tk->buffstart -= pos;
tk->buffcount += pos;
if(mouse_result == TERMKEY_RES_KEY)
if (mouse_result == TERMKEY_RES_KEY) {
*nbytep += pos;
}
return mouse_result;
}
key->type = nk->key.type;
key->code.sym = nk->key.sym;
key->type = nk->key.type;
key->code.sym = nk->key.sym;
key->modifiers = nk->key.modifier_set;
*nbytep = pos;
return TERMKEY_RES_KEY;
@ -583,8 +530,9 @@ static TermKeyResult peekkey(TermKey *tk, void *info, TermKeyKey *key, int force
// If p is not NULL then we hadn't walked off the end yet, so we have a
// partial match
if(p && !force)
if (p && !force) {
return TERMKEY_RES_AGAIN;
}
return TERMKEY_RES_NONE;
}
@ -597,39 +545,42 @@ static int insert_seq(TermKeyTI *ti, const char *seq, struct trie_node *node)
// Unsigned because we'll be using it as an array subscript
unsigned char b;
while((b = seq[pos])) {
while ((b = (unsigned char)seq[pos])) {
struct trie_node *next = lookup_next(p, b);
if(!next)
if (!next) {
break;
}
p = next;
pos++;
}
while((b = seq[pos])) {
while ((b = (unsigned char)seq[pos])) {
struct trie_node *next;
if(seq[pos+1])
if (seq[pos + 1]) {
// Intermediate node
next = new_node_arr(0, 0xff);
else
} else {
// Final key node
next = node;
}
if(!next)
if (!next) {
return 0;
}
switch(p->type) {
case TYPE_ARR:
{
struct trie_node_arr *nar = (struct trie_node_arr*)p;
if(b < nar->min || b > nar->max) {
fprintf(stderr, "ASSERT FAIL: Trie insert at 0x%02x is outside of extent bounds (0x%02x..0x%02x)\n",
b, nar->min, nar->max);
abort();
}
nar->arr[b - nar->min] = next;
p = next;
break;
switch (p->type) {
case TYPE_ARR: {
struct trie_node_arr *nar = (struct trie_node_arr *)p;
if (b < nar->min || b > nar->max) {
fprintf(stderr,
"ASSERT FAIL: Trie insert at 0x%02x is outside of extent bounds (0x%02x..0x%02x)\n",
b, nar->min, nar->max);
abort();
}
nar->arr[b - nar->min] = next;
p = next;
break;
}
case TYPE_KEY:
fprintf(stderr, "ASSERT FAIL: Tried to insert child node in TYPE_KEY\n");
abort();
@ -640,15 +591,3 @@ static int insert_seq(TermKeyTI *ti, const char *seq, struct trie_node *node)
return 1;
}
struct TermKeyDriver termkey_driver_ti = {
.name = "terminfo",
.new_driver = new_driver,
.free_driver = free_driver,
.start_driver = start_driver,
.stop_driver = stop_driver,
.peekkey = peekkey,
};

View File

@ -0,0 +1,7 @@
#pragma once
#include "nvim/tui/termkey/termkey_defs.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "tui/termkey/driver-ti.h.generated.h"
#endif

View File

@ -1,31 +1,29 @@
#ifndef GUARD_TERMKEY_INTERNAL_H_
#define GUARD_TERMKEY_INTERNAL_H_
#pragma once
#include <stdint.h>
#include "nvim/tui/termkey/termkey_defs.h"
#define HAVE_TERMIOS
#ifdef _WIN32
# undef HAVE_TERMIOS
#endif
#include "termkey.h"
#include <stdint.h>
#ifdef HAVE_TERMIOS
# include <termios.h>
#endif
#ifdef _MSC_VER
#include <BaseTsd.h>
# include <BaseTsd.h>
typedef SSIZE_T ssize_t;
#endif
struct TermKeyDriver
{
const char *name;
void *(*new_driver)(TermKey *tk, const char *term);
void (*free_driver)(void *info);
int (*start_driver)(TermKey *tk, void *info);
int (*stop_driver)(TermKey *tk, void *info);
struct TermKeyDriver {
const char *name;
void *(*new_driver)(TermKey *tk, const char *term);
void (*free_driver)(void *info);
int (*start_driver)(TermKey *tk, void *info);
int (*stop_driver)(TermKey *tk, void *info);
TermKeyResult (*peekkey)(TermKey *tk, void *info, TermKeyKey *key, int force, size_t *nbytes);
};
@ -38,21 +36,21 @@ struct keyinfo {
struct TermKeyDriverNode;
struct TermKeyDriverNode {
struct TermKeyDriver *driver;
void *info;
struct TermKeyDriver *driver;
void *info;
struct TermKeyDriverNode *next;
};
struct TermKey {
int fd;
int flags;
int canonflags;
int fd;
int flags;
int canonflags;
unsigned char *buffer;
size_t buffstart; // First offset in buffer
size_t buffcount; // NUMBER of entires valid in buffer
size_t buffsize; // Total malloc'ed size
size_t hightide; /* Position beyond buffstart at which peekkey() should next start
* normally 0, but see also termkey_interpret_csi */
size_t buffstart; // First offset in buffer
size_t buffcount; // NUMBER of entires valid in buffer
size_t buffsize; // Total malloc'ed size
size_t hightide; // Position beyond buffstart at which peekkey() should next start
// normally 0, but see also termkey_interpret_csi
#ifdef HAVE_TERMIOS
struct termios restore_termios;
@ -62,12 +60,12 @@ struct TermKey {
TermKey_Terminfo_Getstr_Hook *ti_getstr_hook;
void *ti_getstr_hook_data;
int waittime; // msec
int waittime; // msec
char is_closed;
char is_started;
char is_closed;
char is_started;
int nkeynames;
int nkeynames;
const char **keynames;
// There are 32 C0 codes
@ -78,7 +76,7 @@ struct TermKey {
// Now some "protected" methods for the driver to call but which we don't
// want exported as real symbols in the library
struct {
void (*emit_codepoint)(TermKey *tk, long codepoint, TermKeyKey *key);
void (*emit_codepoint)(TermKey *tk, int codepoint, TermKeyKey *key);
TermKeyResult (*peekkey_simple)(TermKey *tk, TermKeyKey *key, int force, size_t *nbytes);
TermKeyResult (*peekkey_mouse)(TermKey *tk, TermKeyKey *key, size_t *nbytes);
} method;
@ -86,27 +84,26 @@ struct TermKey {
static inline void termkey_key_get_linecol(const TermKeyKey *key, int *line, int *col)
{
if(col)
*col = (unsigned char)key->code.mouse[1] | ((unsigned char)key->code.mouse[3] & 0x0f) << 8;
if (col) {
*col = (unsigned char)key->code.mouse[1] | ((unsigned char)key->code.mouse[3] & 0x0f) << 8;
}
if(line)
if (line) {
*line = (unsigned char)key->code.mouse[2] | ((unsigned char)key->code.mouse[3] & 0x70) << 4;
}
}
static inline void termkey_key_set_linecol(TermKeyKey *key, int line, int col)
{
if(line > 0xfff)
if (line > 0xfff) {
line = 0xfff;
}
if(col > 0x7ff)
if (col > 0x7ff) {
col = 0x7ff;
}
key->code.mouse[1] = (line & 0x0ff);
key->code.mouse[2] = (col & 0x0ff);
key->code.mouse[1] = (char)(line & 0x0ff);
key->code.mouse[2] = (char)(col & 0x0ff);
key->code.mouse[3] = (line & 0xf00) >> 8 | (col & 0x300) >> 4;
}
extern struct TermKeyDriver termkey_driver_csi;
extern struct TermKeyDriver termkey_driver_ti;
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,10 @@
#pragma once
#include <stdint.h>
#include <stdlib.h>
#include "nvim/tui/termkey/termkey_defs.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "tui/termkey/termkey.h.generated.h"
#endif

View File

@ -0,0 +1,199 @@
#pragma once
#include <stddef.h>
#include <stdint.h>
#include <unibilium.h>
#include <uv.h>
#include "nvim/event/defs.h"
#include "nvim/tui/tui_defs.h"
#include "nvim/types_defs.h"
typedef struct TermKey TermKey;
typedef struct {
TermKey *tk;
int saved_string_id;
char *saved_string;
} TermKeyCsi;
typedef enum {
TERMKEY_RES_NONE,
TERMKEY_RES_KEY,
TERMKEY_RES_EOF,
TERMKEY_RES_AGAIN,
TERMKEY_RES_ERROR,
} TermKeyResult;
typedef enum {
TERMKEY_SYM_UNKNOWN = -1,
TERMKEY_SYM_NONE = 0,
// Special names in C0
TERMKEY_SYM_BACKSPACE,
TERMKEY_SYM_TAB,
TERMKEY_SYM_ENTER,
TERMKEY_SYM_ESCAPE,
// Special names in G0
TERMKEY_SYM_SPACE,
TERMKEY_SYM_DEL,
// Special keys
TERMKEY_SYM_UP,
TERMKEY_SYM_DOWN,
TERMKEY_SYM_LEFT,
TERMKEY_SYM_RIGHT,
TERMKEY_SYM_BEGIN,
TERMKEY_SYM_FIND,
TERMKEY_SYM_INSERT,
TERMKEY_SYM_DELETE,
TERMKEY_SYM_SELECT,
TERMKEY_SYM_PAGEUP,
TERMKEY_SYM_PAGEDOWN,
TERMKEY_SYM_HOME,
TERMKEY_SYM_END,
// Special keys from terminfo
TERMKEY_SYM_CANCEL,
TERMKEY_SYM_CLEAR,
TERMKEY_SYM_CLOSE,
TERMKEY_SYM_COMMAND,
TERMKEY_SYM_COPY,
TERMKEY_SYM_EXIT,
TERMKEY_SYM_HELP,
TERMKEY_SYM_MARK,
TERMKEY_SYM_MESSAGE,
TERMKEY_SYM_MOVE,
TERMKEY_SYM_OPEN,
TERMKEY_SYM_OPTIONS,
TERMKEY_SYM_PRINT,
TERMKEY_SYM_REDO,
TERMKEY_SYM_REFERENCE,
TERMKEY_SYM_REFRESH,
TERMKEY_SYM_REPLACE,
TERMKEY_SYM_RESTART,
TERMKEY_SYM_RESUME,
TERMKEY_SYM_SAVE,
TERMKEY_SYM_SUSPEND,
TERMKEY_SYM_UNDO,
// Numeric keypad special keys
TERMKEY_SYM_KP0,
TERMKEY_SYM_KP1,
TERMKEY_SYM_KP2,
TERMKEY_SYM_KP3,
TERMKEY_SYM_KP4,
TERMKEY_SYM_KP5,
TERMKEY_SYM_KP6,
TERMKEY_SYM_KP7,
TERMKEY_SYM_KP8,
TERMKEY_SYM_KP9,
TERMKEY_SYM_KPENTER,
TERMKEY_SYM_KPPLUS,
TERMKEY_SYM_KPMINUS,
TERMKEY_SYM_KPMULT,
TERMKEY_SYM_KPDIV,
TERMKEY_SYM_KPCOMMA,
TERMKEY_SYM_KPPERIOD,
TERMKEY_SYM_KPEQUALS,
// et cetera ad nauseum
TERMKEY_N_SYMS,
} TermKeySym;
typedef enum {
TERMKEY_TYPE_UNICODE,
TERMKEY_TYPE_FUNCTION,
TERMKEY_TYPE_KEYSYM,
TERMKEY_TYPE_MOUSE,
TERMKEY_TYPE_POSITION,
TERMKEY_TYPE_MODEREPORT,
TERMKEY_TYPE_DCS,
TERMKEY_TYPE_OSC,
// add other recognised types here
TERMKEY_TYPE_UNKNOWN_CSI = -1,
} TermKeyType;
typedef enum {
TERMKEY_MOUSE_UNKNOWN,
TERMKEY_MOUSE_PRESS,
TERMKEY_MOUSE_DRAG,
TERMKEY_MOUSE_RELEASE,
} TermKeyMouseEvent;
enum {
TERMKEY_KEYMOD_SHIFT = 1 << 0,
TERMKEY_KEYMOD_ALT = 1 << 1,
TERMKEY_KEYMOD_CTRL = 1 << 2,
};
typedef struct {
const unsigned char *param;
size_t length;
} TermKeyCsiParam;
enum {
TERMKEY_FLAG_NOINTERPRET = 1 << 0, // Do not interpret C0//DEL codes if possible
TERMKEY_FLAG_CONVERTKP = 1 << 1, // Convert KP codes to regular keypresses
TERMKEY_FLAG_RAW = 1 << 2, // Input is raw bytes, not UTF-8
TERMKEY_FLAG_UTF8 = 1 << 3, // Input is definitely UTF-8
TERMKEY_FLAG_NOTERMIOS = 1 << 4, // Do not make initial termios calls on construction
TERMKEY_FLAG_SPACESYMBOL = 1 << 5, // Sets TERMKEY_CANON_SPACESYMBOL
TERMKEY_FLAG_CTRLC = 1 << 6, // Allow Ctrl-C to be read as normal, disabling SIGINT
TERMKEY_FLAG_EINTR = 1 << 7, // Return ERROR on signal (EINTR) rather than retry
TERMKEY_FLAG_NOSTART = 1 << 8, // Do not call termkey_start() in constructor
};
enum {
TERMKEY_CANON_SPACESYMBOL = 1 << 0, // Space is symbolic rather than Unicode
TERMKEY_CANON_DELBS = 1 << 1, // Del is converted to Backspace
};
typedef struct {
TermKeyType type;
union {
int codepoint; // TERMKEY_TYPE_UNICODE
int number; // TERMKEY_TYPE_FUNCTION
TermKeySym sym; // TERMKEY_TYPE_KEYSYM
char mouse[4]; // TERMKEY_TYPE_MOUSE
// opaque. see termkey_interpret_mouse
} code;
int modifiers;
// Any Unicode character can be UTF-8 encoded in no more than 6 bytes, plus
// terminating NUL
char utf8[7];
} TermKeyKey;
// Mostly-undocumented hooks for doing evil evil things
typedef const char *TermKey_Terminfo_Getstr_Hook(const char *name, const char *value, void *data);
typedef enum {
TERMKEY_FORMAT_LONGMOD = 1 << 0, // Shift-... instead of S-...
TERMKEY_FORMAT_CARETCTRL = 1 << 1, // ^X instead of C-X
TERMKEY_FORMAT_ALTISMETA = 1 << 2, // Meta- or M- instead of Alt- or A-
TERMKEY_FORMAT_WRAPBRACKET = 1 << 3, // Wrap special keys in brackets like <Escape>
TERMKEY_FORMAT_SPACEMOD = 1 << 4, // M Foo instead of M-Foo
TERMKEY_FORMAT_LOWERMOD = 1 << 5, // meta or m instead of Meta or M
TERMKEY_FORMAT_LOWERSPACE = 1 << 6, // page down instead of PageDown
TERMKEY_FORMAT_MOUSE_POS = 1 << 8, // Include mouse position if relevant; @ col,line
} TermKeyFormat;
// Some useful combinations
#define TERMKEY_FORMAT_VIM (TermKeyFormat)(TERMKEY_FORMAT_ALTISMETA|TERMKEY_FORMAT_WRAPBRACKET)
typedef struct {
TermKey *tk;
unibi_term *unibi; // only valid until first 'start' call
struct trie_node *root;
char *start_string;
char *stop_string;
} TermKeyTI;

File diff suppressed because it is too large Load Diff

View File

@ -1,256 +0,0 @@
#ifdef __cplusplus
extern "C" {
#endif
#ifndef GUARD_TERMKEY_H_
#define GUARD_TERMKEY_H_
#include <stdint.h>
#include <stdlib.h>
#define TERMKEY_VERSION_MAJOR 0
#define TERMKEY_VERSION_MINOR 22
#define TERMKEY_CHECK_VERSION \
termkey_check_version(TERMKEY_VERSION_MAJOR, TERMKEY_VERSION_MINOR)
typedef enum {
TERMKEY_SYM_UNKNOWN = -1,
TERMKEY_SYM_NONE = 0,
/* Special names in C0 */
TERMKEY_SYM_BACKSPACE,
TERMKEY_SYM_TAB,
TERMKEY_SYM_ENTER,
TERMKEY_SYM_ESCAPE,
/* Special names in G0 */
TERMKEY_SYM_SPACE,
TERMKEY_SYM_DEL,
/* Special keys */
TERMKEY_SYM_UP,
TERMKEY_SYM_DOWN,
TERMKEY_SYM_LEFT,
TERMKEY_SYM_RIGHT,
TERMKEY_SYM_BEGIN,
TERMKEY_SYM_FIND,
TERMKEY_SYM_INSERT,
TERMKEY_SYM_DELETE,
TERMKEY_SYM_SELECT,
TERMKEY_SYM_PAGEUP,
TERMKEY_SYM_PAGEDOWN,
TERMKEY_SYM_HOME,
TERMKEY_SYM_END,
/* Special keys from terminfo */
TERMKEY_SYM_CANCEL,
TERMKEY_SYM_CLEAR,
TERMKEY_SYM_CLOSE,
TERMKEY_SYM_COMMAND,
TERMKEY_SYM_COPY,
TERMKEY_SYM_EXIT,
TERMKEY_SYM_HELP,
TERMKEY_SYM_MARK,
TERMKEY_SYM_MESSAGE,
TERMKEY_SYM_MOVE,
TERMKEY_SYM_OPEN,
TERMKEY_SYM_OPTIONS,
TERMKEY_SYM_PRINT,
TERMKEY_SYM_REDO,
TERMKEY_SYM_REFERENCE,
TERMKEY_SYM_REFRESH,
TERMKEY_SYM_REPLACE,
TERMKEY_SYM_RESTART,
TERMKEY_SYM_RESUME,
TERMKEY_SYM_SAVE,
TERMKEY_SYM_SUSPEND,
TERMKEY_SYM_UNDO,
/* Numeric keypad special keys */
TERMKEY_SYM_KP0,
TERMKEY_SYM_KP1,
TERMKEY_SYM_KP2,
TERMKEY_SYM_KP3,
TERMKEY_SYM_KP4,
TERMKEY_SYM_KP5,
TERMKEY_SYM_KP6,
TERMKEY_SYM_KP7,
TERMKEY_SYM_KP8,
TERMKEY_SYM_KP9,
TERMKEY_SYM_KPENTER,
TERMKEY_SYM_KPPLUS,
TERMKEY_SYM_KPMINUS,
TERMKEY_SYM_KPMULT,
TERMKEY_SYM_KPDIV,
TERMKEY_SYM_KPCOMMA,
TERMKEY_SYM_KPPERIOD,
TERMKEY_SYM_KPEQUALS,
/* et cetera ad nauseum */
TERMKEY_N_SYMS
} TermKeySym;
typedef enum {
TERMKEY_TYPE_UNICODE,
TERMKEY_TYPE_FUNCTION,
TERMKEY_TYPE_KEYSYM,
TERMKEY_TYPE_MOUSE,
TERMKEY_TYPE_POSITION,
TERMKEY_TYPE_MODEREPORT,
TERMKEY_TYPE_DCS,
TERMKEY_TYPE_OSC,
/* add other recognised types here */
TERMKEY_TYPE_UNKNOWN_CSI = -1
} TermKeyType;
typedef enum {
TERMKEY_RES_NONE,
TERMKEY_RES_KEY,
TERMKEY_RES_EOF,
TERMKEY_RES_AGAIN,
TERMKEY_RES_ERROR
} TermKeyResult;
typedef enum {
TERMKEY_MOUSE_UNKNOWN,
TERMKEY_MOUSE_PRESS,
TERMKEY_MOUSE_DRAG,
TERMKEY_MOUSE_RELEASE
} TermKeyMouseEvent;
enum {
TERMKEY_KEYMOD_SHIFT = 1 << 0,
TERMKEY_KEYMOD_ALT = 1 << 1,
TERMKEY_KEYMOD_CTRL = 1 << 2
};
typedef struct {
TermKeyType type;
union {
long codepoint; /* TERMKEY_TYPE_UNICODE */
int number; /* TERMKEY_TYPE_FUNCTION */
TermKeySym sym; /* TERMKEY_TYPE_KEYSYM */
char mouse[4]; /* TERMKEY_TYPE_MOUSE */
/* opaque. see termkey_interpret_mouse */
} code;
int modifiers;
/* Any Unicode character can be UTF-8 encoded in no more than 6 bytes, plus
* terminating NUL */
char utf8[7];
} TermKeyKey;
typedef struct {
const unsigned char *param;
size_t length;
} TermKeyCsiParam;
typedef struct TermKey TermKey;
enum {
TERMKEY_FLAG_NOINTERPRET = 1 << 0, /* Do not interpret C0//DEL codes if possible */
TERMKEY_FLAG_CONVERTKP = 1 << 1, /* Convert KP codes to regular keypresses */
TERMKEY_FLAG_RAW = 1 << 2, /* Input is raw bytes, not UTF-8 */
TERMKEY_FLAG_UTF8 = 1 << 3, /* Input is definitely UTF-8 */
TERMKEY_FLAG_NOTERMIOS = 1 << 4, /* Do not make initial termios calls on construction */
TERMKEY_FLAG_SPACESYMBOL = 1 << 5, /* Sets TERMKEY_CANON_SPACESYMBOL */
TERMKEY_FLAG_CTRLC = 1 << 6, /* Allow Ctrl-C to be read as normal, disabling SIGINT */
TERMKEY_FLAG_EINTR = 1 << 7, /* Return ERROR on signal (EINTR) rather than retry */
TERMKEY_FLAG_NOSTART = 1 << 8 /* Do not call termkey_start() in constructor */
};
enum {
TERMKEY_CANON_SPACESYMBOL = 1 << 0, /* Space is symbolic rather than Unicode */
TERMKEY_CANON_DELBS = 1 << 1 /* Del is converted to Backspace */
};
void termkey_check_version(int major, int minor);
TermKey *termkey_new(int fd, int flags);
TermKey *termkey_new_abstract(const char *term, int flags);
void termkey_free(TermKey *tk);
void termkey_destroy(TermKey *tk);
/* Mostly-undocumented hooks for doing evil evil things */
typedef const char *TermKey_Terminfo_Getstr_Hook(const char *name, const char *value, void *data);
void termkey_hook_terminfo_getstr(TermKey *tk, TermKey_Terminfo_Getstr_Hook *hookfn, void *data);
int termkey_start(TermKey *tk);
int termkey_stop(TermKey *tk);
int termkey_is_started(TermKey *tk);
int termkey_get_fd(TermKey *tk);
int termkey_get_flags(TermKey *tk);
void termkey_set_flags(TermKey *tk, int newflags);
int termkey_get_waittime(TermKey *tk);
void termkey_set_waittime(TermKey *tk, int msec);
int termkey_get_canonflags(TermKey *tk);
void termkey_set_canonflags(TermKey *tk, int);
size_t termkey_get_buffer_size(TermKey *tk);
int termkey_set_buffer_size(TermKey *tk, size_t size);
size_t termkey_get_buffer_remaining(TermKey *tk);
void termkey_canonicalise(TermKey *tk, TermKeyKey *key);
TermKeyResult termkey_getkey(TermKey *tk, TermKeyKey *key);
TermKeyResult termkey_getkey_force(TermKey *tk, TermKeyKey *key);
TermKeyResult termkey_waitkey(TermKey *tk, TermKeyKey *key);
TermKeyResult termkey_advisereadable(TermKey *tk);
size_t termkey_push_bytes(TermKey *tk, const char *bytes, size_t len);
TermKeySym termkey_register_keyname(TermKey *tk, TermKeySym sym, const char *name);
const char *termkey_get_keyname(TermKey *tk, TermKeySym sym);
const char *termkey_lookup_keyname(TermKey *tk, const char *str, TermKeySym *sym);
TermKeySym termkey_keyname2sym(TermKey *tk, const char *keyname);
TermKeyResult termkey_interpret_mouse(TermKey *tk, const TermKeyKey *key, TermKeyMouseEvent *event, int *button, int *line, int *col);
TermKeyResult termkey_interpret_position(TermKey *tk, const TermKeyKey *key, int *line, int *col);
TermKeyResult termkey_interpret_modereport(TermKey *tk, const TermKeyKey *key, int *initial, int *mode, int *value);
TermKeyResult termkey_interpret_csi(TermKey *tk, const TermKeyKey *key, TermKeyCsiParam params[], size_t *nparams, unsigned long *cmd);
TermKeyResult termkey_interpret_csi_param(TermKeyCsiParam param, long *paramp, long subparams[], size_t *nsubparams);
TermKeyResult termkey_interpret_string(TermKey *tk, const TermKeyKey *key, const char **strp);
typedef enum {
TERMKEY_FORMAT_LONGMOD = 1 << 0, /* Shift-... instead of S-... */
TERMKEY_FORMAT_CARETCTRL = 1 << 1, /* ^X instead of C-X */
TERMKEY_FORMAT_ALTISMETA = 1 << 2, /* Meta- or M- instead of Alt- or A- */
TERMKEY_FORMAT_WRAPBRACKET = 1 << 3, /* Wrap special keys in brackets like <Escape> */
TERMKEY_FORMAT_SPACEMOD = 1 << 4, /* M Foo instead of M-Foo */
TERMKEY_FORMAT_LOWERMOD = 1 << 5, /* meta or m instead of Meta or M */
TERMKEY_FORMAT_LOWERSPACE = 1 << 6, /* page down instead of PageDown */
TERMKEY_FORMAT_MOUSE_POS = 1 << 8 /* Include mouse position if relevant; @ col,line */
} TermKeyFormat;
/* Some useful combinations */
#define TERMKEY_FORMAT_VIM (TermKeyFormat)(TERMKEY_FORMAT_ALTISMETA|TERMKEY_FORMAT_WRAPBRACKET)
#define TERMKEY_FORMAT_URWID (TermKeyFormat)(TERMKEY_FORMAT_LONGMOD|TERMKEY_FORMAT_ALTISMETA| \
TERMKEY_FORMAT_LOWERMOD|TERMKEY_FORMAT_SPACEMOD|TERMKEY_FORMAT_LOWERSPACE)
size_t termkey_strfkey(TermKey *tk, char *buffer, size_t len, TermKeyKey *key, TermKeyFormat format);
const char *termkey_strpkey(TermKey *tk, const char *str, TermKeyKey *key, TermKeyFormat format);
int termkey_keycmp(TermKey *tk, const TermKeyKey *key1, const TermKeyKey *key2);
#endif
#ifdef __cplusplus
}
#endif

View File

@ -1,8 +1,7 @@
#include "vterm_internal.h"
#include <stdio.h>
#include "utf8.h"
#include "nvim/tui/termkey/termkey.h"
void vterm_keyboard_unichar(VTerm *vt, uint32_t c, VTermModifier mod)
{

View File

@ -1,6 +1,6 @@
#include "vterm_internal.h"
#include "utf8.h"
#include "nvim/tui/termkey/termkey.h"
static void output_mouse(VTermState *state, int code, int pressed, int modifiers, int col, int row)
{

View File

@ -2,9 +2,10 @@
#include <stdio.h>
#include <string.h>
#include "nvim/mbyte.h"
#include "nvim/tui/termkey/termkey.h"
#include "rect.h"
#include "utf8.h"
#define UNICODE_SPACE 0x20
#define UNICODE_LINEFEED 0x0a
@ -922,7 +923,7 @@ static size_t _get_chars(const VTermScreen *screen, const int utf8, void *buffer
#define PUT(c) \
if(utf8) { \
size_t thislen = utf8_seqlen(c); \
size_t thislen = utf_char2len(c); \
if(buffer && outpos + thislen <= len) \
outpos += fill_utf8((c), (char *)buffer + outpos); \
else \

View File

@ -1,39 +0,0 @@
/* The following functions copied and adapted from libtermkey
*
* http://www.leonerd.org.uk/code/libtermkey/
*/
static inline unsigned int utf8_seqlen(long codepoint)
{
if(codepoint < 0x0000080) return 1;
if(codepoint < 0x0000800) return 2;
if(codepoint < 0x0010000) return 3;
if(codepoint < 0x0200000) return 4;
if(codepoint < 0x4000000) return 5;
return 6;
}
/* Does NOT NUL-terminate the buffer */
static int fill_utf8(long codepoint, char *str)
{
int nbytes = utf8_seqlen(codepoint);
// This is easier done backwards
int b = nbytes;
while(b > 1) {
b--;
str[b] = 0x80 | (codepoint & 0x3f);
codepoint >>= 6;
}
switch(nbytes) {
case 1: str[0] = (codepoint & 0x7f); break;
case 2: str[0] = 0xc0 | (codepoint & 0x1f); break;
case 3: str[0] = 0xe0 | (codepoint & 0x0f); break;
case 4: str[0] = 0xf0 | (codepoint & 0x07); break;
case 5: str[0] = 0xf8 | (codepoint & 0x03); break;
case 6: str[0] = 0xfc | (codepoint & 0x01); break;
}
return nbytes;
}
/* end copy */