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

@ -1,36 +1,37 @@
#include "termkey.h"
#include "termkey-internal.h"
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include "nvim/memory.h"
#include "nvim/tui/termkey/driver-csi.h"
#include "nvim/tui/termkey/termkey-internal.h"
#include "nvim/tui/termkey/termkey.h"
#include "nvim/tui/termkey/termkey_defs.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "tui/termkey/driver-csi.c.generated.h"
#endif
// There are 64 codes 0x40 - 0x7F
static int keyinfo_initialised = 0;
static struct keyinfo ss3s[64];
static char ss3_kpalts[64];
typedef struct {
TermKey *tk;
int saved_string_id;
char *saved_string;
} TermKeyCsi;
typedef TermKeyResult CsiHandler(TermKey *tk, TermKeyKey *key, int cmd, TermKeyCsiParam *params, int nparams);
typedef TermKeyResult CsiHandler(TermKey *tk, TermKeyKey *key, int cmd, TermKeyCsiParam *params,
int nparams);
static CsiHandler *csi_handlers[64];
/*
* Handler for CSI/SS3 cmd keys
*/
// Handler for CSI/SS3 cmd keys
static struct keyinfo csi_ss3s[64];
static TermKeyResult handle_csi_ss3_full(TermKey *tk, TermKeyKey *key, int cmd, TermKeyCsiParam *params, int nparams)
static TermKeyResult handle_csi_ss3_full(TermKey *tk, TermKeyKey *key, int cmd,
TermKeyCsiParam *params, int nparams)
{
TermKeyResult result = TERMKEY_RES_KEY;
if(nparams > 1 && params[1].param != NULL) {
long arg = 0;
if (nparams > 1 && params[1].param != NULL) {
int arg = 0;
result = termkey_interpret_csi_param(params[1], &arg, NULL, NULL);
if (result != TERMKEY_RES_KEY) {
return result;
@ -46,15 +47,17 @@ static TermKeyResult handle_csi_ss3_full(TermKey *tk, TermKeyKey *key, int cmd,
key->modifiers &= ~(csi_ss3s[cmd - 0x40].modifier_mask);
key->modifiers |= csi_ss3s[cmd - 0x40].modifier_set;
if(key->code.sym == TERMKEY_SYM_UNKNOWN)
if (key->code.sym == TERMKEY_SYM_UNKNOWN) {
result = TERMKEY_RES_NONE;
}
return result;
}
static void register_csi_ss3_full(TermKeyType type, TermKeySym sym, int modifier_set, int modifier_mask, unsigned char cmd)
static void register_csi_ss3_full(TermKeyType type, TermKeySym sym, int modifier_set,
int modifier_mask, unsigned char cmd)
{
if(cmd < 0x40 || cmd >= 0x80) {
if (cmd < 0x40 || cmd >= 0x80) {
return;
}
@ -71,13 +74,10 @@ static void register_csi_ss3(TermKeyType type, TermKeySym sym, unsigned char cmd
register_csi_ss3_full(type, sym, 0, 0, cmd);
}
/*
* Handler for SS3 keys with kpad alternate representations
*/
/// Handler for SS3 keys with kpad alternate representations
static void register_ss3kpalt(TermKeyType type, TermKeySym sym, unsigned char cmd, char kpalt)
{
if(cmd < 0x40 || cmd >= 0x80) {
if (cmd < 0x40 || cmd >= 0x80) {
return;
}
@ -88,23 +88,22 @@ static void register_ss3kpalt(TermKeyType type, TermKeySym sym, unsigned char cm
ss3_kpalts[cmd - 0x40] = kpalt;
}
/*
* Handler for CSI number ~ function keys
*/
// Handler for CSI number ~ function keys
static struct keyinfo csifuncs[35]; /* This value must be increased if more CSI function keys are added */
#define NCSIFUNCS (sizeof(csifuncs)/sizeof(csifuncs[0]))
#define NCSIFUNCS 35 // This value must be increased if more CSI function keys are added
static struct keyinfo csifuncs[NCSIFUNCS];
static TermKeyResult handle_csifunc(TermKey *tk, TermKeyKey *key, int cmd, TermKeyCsiParam *params, int nparams)
static TermKeyResult handle_csifunc(TermKey *tk, TermKeyKey *key, int cmd, TermKeyCsiParam *params,
int nparams)
{
if (nparams == 0) {
return TERMKEY_RES_NONE;
}
TermKeyResult result = TERMKEY_RES_KEY;
long args[3];
int args[3];
if(nparams > 1 && params[1].param != NULL) {
if (nparams > 1 && params[1].param != NULL) {
result = termkey_interpret_csi_param(params[1], &args[1], NULL, NULL);
if (result != TERMKEY_RES_KEY) {
return result;
@ -122,7 +121,7 @@ static TermKeyResult handle_csifunc(TermKey *tk, TermKeyKey *key, int cmd, TermK
return result;
}
if(args[0] == 27 && nparams > 2 && params[2].param != NULL) {
if (args[0] == 27 && nparams > 2 && params[2].param != NULL) {
result = termkey_interpret_csi_param(params[2], &args[2], NULL, NULL);
if (result != TERMKEY_RES_KEY) {
return result;
@ -131,17 +130,16 @@ static TermKeyResult handle_csifunc(TermKey *tk, TermKeyKey *key, int cmd, TermK
int mod = key->modifiers;
(*tk->method.emit_codepoint)(tk, args[2], key);
key->modifiers |= mod;
}
else if(args[0] >= 0 && args[0] < NCSIFUNCS) {
} else if (args[0] >= 0 && args[0] < NCSIFUNCS) {
key->type = csifuncs[args[0]].type;
key->code.sym = csifuncs[args[0]].sym;
key->modifiers &= ~(csifuncs[args[0]].modifier_mask);
key->modifiers |= csifuncs[args[0]].modifier_set;
}
else
} else {
key->code.sym = TERMKEY_SYM_UNKNOWN;
}
if(key->code.sym == TERMKEY_SYM_UNKNOWN) {
if (key->code.sym == TERMKEY_SYM_UNKNOWN) {
#ifdef DEBUG
fprintf(stderr, "CSI: Unknown function key %ld\n", arg[0]);
#endif
@ -153,7 +151,7 @@ static TermKeyResult handle_csifunc(TermKey *tk, TermKeyKey *key, int cmd, TermK
static void register_csifunc(TermKeyType type, TermKeySym sym, int number)
{
if(number >= NCSIFUNCS) {
if (number >= NCSIFUNCS) {
return;
}
@ -165,19 +163,18 @@ static void register_csifunc(TermKeyType type, TermKeySym sym, int number)
csi_handlers['~' - 0x40] = &handle_csifunc;
}
/*
* Handler for CSI u extended Unicode keys
*/
static TermKeyResult handle_csi_u(TermKey *tk, TermKeyKey *key, int cmd, TermKeyCsiParam *params, int nparams)
/// Handler for CSI u extended Unicode keys
static TermKeyResult handle_csi_u(TermKey *tk, TermKeyKey *key, int cmd, TermKeyCsiParam *params,
int nparams)
{
switch(cmd) {
switch (cmd) {
case 'u': {
long args[2];
if(nparams > 1 && params[1].param != NULL) {
long subparam = 0;
int args[2];
if (nparams > 1 && params[1].param != NULL) {
int subparam = 0;
size_t nsubparams = 1;
if (termkey_interpret_csi_param(params[1], &args[1], &subparam, &nsubparams) != TERMKEY_RES_KEY) {
if (termkey_interpret_csi_param(params[1], &args[1], &subparam,
&nsubparams) != TERMKEY_RES_KEY) {
return TERMKEY_RES_ERROR;
}
@ -207,17 +204,15 @@ static TermKeyResult handle_csi_u(TermKey *tk, TermKeyKey *key, int cmd, TermKey
}
}
/*
* Handler for CSI M / CSI m mouse events in SGR and rxvt encodings
* Note: This does not handle X10 encoding
*/
static TermKeyResult handle_csi_m(TermKey *tk, TermKeyKey *key, int cmd, TermKeyCsiParam *params, int nparams)
/// Handler for CSI M / CSI m mouse events in SGR and rxvt encodings
/// Note: This does not handle X10 encoding
static TermKeyResult handle_csi_m(TermKey *tk, TermKeyKey *key, int cmd, TermKeyCsiParam *params,
int nparams)
{
int initial = cmd >> 8;
cmd &= 0xff;
switch(cmd) {
switch (cmd) {
case 'M':
case 'm':
break;
@ -229,16 +224,16 @@ static TermKeyResult handle_csi_m(TermKey *tk, TermKeyKey *key, int cmd, TermKey
return TERMKEY_RES_NONE;
}
long args[3];
int args[3];
for (size_t i = 0; i < 3; i++) {
if (termkey_interpret_csi_param(params[i], &args[i], NULL, NULL) != TERMKEY_RES_KEY) {
return TERMKEY_RES_ERROR;
}
}
if(!initial) { // rxvt protocol
if (!initial) { // rxvt protocol
key->type = TERMKEY_TYPE_MOUSE;
key->code.mouse[0] = args[0];
key->code.mouse[0] = (char)args[0];
key->modifiers = (key->code.mouse[0] & 0x1c) >> 2;
key->code.mouse[0] &= ~0x1c;
@ -248,17 +243,18 @@ static TermKeyResult handle_csi_m(TermKey *tk, TermKeyKey *key, int cmd, TermKey
return TERMKEY_RES_KEY;
}
if(initial == '<') { // SGR protocol
if (initial == '<') { // SGR protocol
key->type = TERMKEY_TYPE_MOUSE;
key->code.mouse[0] = args[0];
key->code.mouse[0] = (char)args[0];
key->modifiers = (key->code.mouse[0] & 0x1c) >> 2;
key->code.mouse[0] &= ~0x1c;
termkey_key_set_linecol(key, args[1], args[2]);
if(cmd == 'm') // release
if (cmd == 'm') { // release
key->code.mouse[3] |= 0x80;
}
return TERMKEY_RES_KEY;
}
@ -266,28 +262,32 @@ static TermKeyResult handle_csi_m(TermKey *tk, TermKeyKey *key, int cmd, TermKey
return TERMKEY_RES_NONE;
}
TermKeyResult termkey_interpret_mouse(TermKey *tk, const TermKeyKey *key, TermKeyMouseEvent *event, int *button, int *line, int *col)
TermKeyResult termkey_interpret_mouse(TermKey *tk, const TermKeyKey *key, TermKeyMouseEvent *event,
int *button, int *line, int *col)
{
if(key->type != TERMKEY_TYPE_MOUSE)
if (key->type != TERMKEY_TYPE_MOUSE) {
return TERMKEY_RES_NONE;
}
if(button)
if (button) {
*button = 0;
}
termkey_key_get_linecol(key, line, col);
if(!event)
if (!event) {
return TERMKEY_RES_KEY;
}
int btn = 0;
int code = key->code.mouse[0];
int code = (unsigned char)key->code.mouse[0];
int drag = code & 0x20;
code &= ~0x3c;
switch(code) {
switch (code) {
case 0:
case 1:
case 2:
@ -312,28 +312,29 @@ TermKeyResult termkey_interpret_mouse(TermKey *tk, const TermKeyKey *key, TermKe
*event = TERMKEY_MOUSE_UNKNOWN;
}
if(button)
if (button) {
*button = btn;
}
if(key->code.mouse[3] & 0x80)
if (key->code.mouse[3] & 0x80) {
*event = TERMKEY_MOUSE_RELEASE;
}
return TERMKEY_RES_KEY;
}
/*
* Handler for CSI ? R position reports
* A plain CSI R with no arguments is probably actually <F3>
*/
static TermKeyResult handle_csi_R(TermKey *tk, TermKeyKey *key, int cmd, TermKeyCsiParam *params, int nparams)
/// Handler for CSI ? R position reports
/// A plain CSI R with no arguments is probably actually <F3>
static TermKeyResult handle_csi_R(TermKey *tk, TermKeyKey *key, int cmd, TermKeyCsiParam *params,
int nparams)
{
switch(cmd) {
case 'R'|'?'<<8:
if(nparams < 2)
switch (cmd) {
case 'R'|'?' << 8:
if (nparams < 2) {
return TERMKEY_RES_NONE;
}
long args[2];
int args[2];
if (termkey_interpret_csi_param(params[0], &args[0], NULL, NULL) != TERMKEY_RES_KEY) {
return TERMKEY_RES_ERROR;
}
@ -353,27 +354,27 @@ static TermKeyResult handle_csi_R(TermKey *tk, TermKeyKey *key, int cmd, TermKey
TermKeyResult termkey_interpret_position(TermKey *tk, const TermKeyKey *key, int *line, int *col)
{
if(key->type != TERMKEY_TYPE_POSITION)
if (key->type != TERMKEY_TYPE_POSITION) {
return TERMKEY_RES_NONE;
}
termkey_key_get_linecol(key, line, col);
return TERMKEY_RES_KEY;
}
/*
* Handler for CSI $y mode status reports
*/
static TermKeyResult handle_csi_y(TermKey *tk, TermKeyKey *key, int cmd, TermKeyCsiParam *params, int nparams)
/// Handler for CSI $y mode status reports
static TermKeyResult handle_csi_y(TermKey *tk, TermKeyKey *key, int cmd, TermKeyCsiParam *params,
int nparams)
{
switch(cmd) {
case 'y'|'$'<<16:
case 'y'|'$'<<16 | '?'<<8:
if(nparams < 2)
switch (cmd) {
case 'y'|'$' << 16:
case 'y'|'$' << 16 | '?' << 8:
if (nparams < 2) {
return TERMKEY_RES_NONE;
}
long args[2];
int args[2];
if (termkey_interpret_csi_param(params[0], &args[0], NULL, NULL) != TERMKEY_RES_KEY) {
return TERMKEY_RES_ERROR;
}
@ -383,10 +384,10 @@ static TermKeyResult handle_csi_y(TermKey *tk, TermKeyKey *key, int cmd, TermKey
}
key->type = TERMKEY_TYPE_MODEREPORT;
key->code.mouse[0] = (cmd >> 8);
key->code.mouse[1] = args[0] >> 8;
key->code.mouse[2] = args[0] & 0xff;
key->code.mouse[3] = args[1];
key->code.mouse[0] = (char)(cmd >> 8);
key->code.mouse[1] = (char)(args[0] >> 8);
key->code.mouse[2] = (char)(args[0] & 0xff);
key->code.mouse[3] = (char)args[1];
return TERMKEY_RES_KEY;
default:
@ -394,37 +395,45 @@ static TermKeyResult handle_csi_y(TermKey *tk, TermKeyKey *key, int cmd, TermKey
}
}
TermKeyResult termkey_interpret_modereport(TermKey *tk, const TermKeyKey *key, int *initial, int *mode, int *value)
TermKeyResult termkey_interpret_modereport(TermKey *tk, const TermKeyKey *key, int *initial,
int *mode, int *value)
{
if(key->type != TERMKEY_TYPE_MODEREPORT)
if (key->type != TERMKEY_TYPE_MODEREPORT) {
return TERMKEY_RES_NONE;
}
if(initial)
*initial = key->code.mouse[0];
if (initial) {
*initial = (unsigned char)key->code.mouse[0];
}
if(mode)
if (mode) {
*mode = ((uint8_t)key->code.mouse[1] << 8) | (uint8_t)key->code.mouse[2];
}
if(value)
*value = key->code.mouse[3];
if (value) {
*value = (unsigned char)key->code.mouse[3];
}
return TERMKEY_RES_KEY;
}
#define CHARAT(i) (tk->buffer[tk->buffstart + (i)])
static TermKeyResult parse_csi(TermKey *tk, size_t introlen, size_t *csi_len, TermKeyCsiParam params[], size_t *nargs, unsigned long *commandp)
static TermKeyResult parse_csi(TermKey *tk, size_t introlen, size_t *csi_len,
TermKeyCsiParam params[], size_t *nargs, unsigned *commandp)
{
size_t csi_end = introlen;
while(csi_end < tk->buffcount) {
if(CHARAT(csi_end) >= 0x40 && CHARAT(csi_end) < 0x80)
while (csi_end < tk->buffcount) {
if (CHARAT(csi_end) >= 0x40 && CHARAT(csi_end) < 0x80) {
break;
}
csi_end++;
}
if(csi_end >= tk->buffcount)
if (csi_end >= tk->buffcount) {
return TERMKEY_RES_AGAIN;
}
unsigned char cmd = CHARAT(csi_end);
*commandp = cmd;
@ -435,66 +444,69 @@ static TermKeyResult parse_csi(TermKey *tk, size_t introlen, size_t *csi_len, Te
size_t p = introlen;
// See if there is an initial byte
if(CHARAT(p) >= '<' && CHARAT(p) <= '?') {
*commandp |= (CHARAT(p) << 8);
if (CHARAT(p) >= '<' && CHARAT(p) <= '?') {
*commandp |= (unsigned)(CHARAT(p) << 8);
p++;
}
// Now attempt to parse out up number;number;... separated values
while(p < csi_end) {
while (p < csi_end) {
unsigned char c = CHARAT(p);
if(c >= '0' && c < ';') {
if(!present) {
if (c >= '0' && c < ';') {
if (!present) {
params[argi].param = &CHARAT(p);
present = 1;
}
}
else if(c == ';') {
if(!present) {
} else if (c == ';') {
if (!present) {
params[argi].param = NULL;
params[argi].length = 0;
} else {
params[argi].length = &CHARAT(p) - params[argi].param;
params[argi].length = (size_t)(&CHARAT(p) - params[argi].param);
}
present = 0;
argi++;
if(argi > 16)
if (argi > 16) {
break;
}
else if(c >= 0x20 && c <= 0x2f) {
*commandp |= c << 16;
} else if (c >= 0x20 && c <= 0x2f) {
*commandp |= (unsigned)(c << 16);
break;
}
p++;
}
if(present) {
params[argi].length = &CHARAT(p) - params[argi].param;
if (present) {
params[argi].length = (size_t)(&CHARAT(p) - params[argi].param);
argi++;
}
*nargs = argi;
*nargs = (size_t)argi;
*csi_len = csi_end + 1;
return TERMKEY_RES_KEY;
}
TermKeyResult termkey_interpret_csi(TermKey *tk, const TermKeyKey *key, TermKeyCsiParam params[], size_t *nparams, unsigned long *cmd)
TermKeyResult termkey_interpret_csi(TermKey *tk, const TermKeyKey *key, TermKeyCsiParam params[],
size_t *nparams, unsigned *cmd)
{
size_t dummy;
if(tk->hightide == 0)
if (tk->hightide == 0) {
return TERMKEY_RES_NONE;
if(key->type != TERMKEY_TYPE_UNKNOWN_CSI)
}
if (key->type != TERMKEY_TYPE_UNKNOWN_CSI) {
return TERMKEY_RES_NONE;
}
return parse_csi(tk, 0, &dummy, params, nparams, cmd);
}
TermKeyResult termkey_interpret_csi_param(TermKeyCsiParam param, long *paramp, long subparams[], size_t *nsubparams)
TermKeyResult termkey_interpret_csi_param(TermKeyCsiParam param, int *paramp, int subparams[],
size_t *nsubparams)
{
if (paramp == NULL) {
return TERMKEY_RES_ERROR;
@ -508,7 +520,7 @@ TermKeyResult termkey_interpret_csi_param(TermKeyCsiParam param, long *paramp, l
return TERMKEY_RES_KEY;
}
long arg = 0;
int arg = 0;
size_t i = 0;
size_t capacity = nsubparams ? *nsubparams : 0;
size_t length = 0;
@ -547,14 +559,15 @@ static int register_keys(void)
{
int i;
for(i = 0; i < 64; i++) {
for (i = 0; i < 64; i++) {
csi_ss3s[i].sym = TERMKEY_SYM_UNKNOWN;
ss3s[i].sym = TERMKEY_SYM_UNKNOWN;
ss3_kpalts[i] = 0;
}
for(i = 0; i < NCSIFUNCS; i++)
for (i = 0; i < NCSIFUNCS; i++) {
csifuncs[i].sym = TERMKEY_SYM_UNKNOWN;
}
register_csi_ss3(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_UP, 'A');
register_csi_ss3(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_DOWN, 'B');
@ -568,7 +581,8 @@ static int register_keys(void)
register_csi_ss3(TERMKEY_TYPE_FUNCTION, 3, 'R');
register_csi_ss3(TERMKEY_TYPE_FUNCTION, 4, 'S');
register_csi_ss3_full(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_TAB, TERMKEY_KEYMOD_SHIFT, TERMKEY_KEYMOD_SHIFT, 'Z');
register_csi_ss3_full(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_TAB, TERMKEY_KEYMOD_SHIFT,
TERMKEY_KEYMOD_SHIFT, 'Z');
register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KPENTER, 'M', 0);
register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KPEQUALS, 'X', '=');
@ -632,15 +646,15 @@ static int register_keys(void)
return 1;
}
static void *new_driver(TermKey *tk, const char *term)
void *new_driver_csi(TermKey *tk, const char *term)
{
if(!keyinfo_initialised)
if(!register_keys())
if (!keyinfo_initialised) {
if (!register_keys()) {
return NULL;
}
}
TermKeyCsi *csi = malloc(sizeof *csi);
if(!csi)
return NULL;
TermKeyCsi *csi = xmalloc(sizeof *csi);
csi->tk = tk;
csi->saved_string_id = 0;
@ -649,28 +663,31 @@ static void *new_driver(TermKey *tk, const char *term)
return csi;
}
static void free_driver(void *info)
void free_driver_csi(void *info)
{
TermKeyCsi *csi = info;
if(csi->saved_string)
free(csi->saved_string);
if (csi->saved_string) {
xfree(csi->saved_string);
}
free(csi);
xfree(csi);
}
static TermKeyResult peekkey_csi(TermKey *tk, TermKeyCsi *csi, size_t introlen, TermKeyKey *key, int force, size_t *nbytep)
static TermKeyResult peekkey_csi_csi(TermKey *tk, TermKeyCsi *csi, size_t introlen, TermKeyKey *key,
int force, size_t *nbytep)
{
size_t csi_len;
size_t nparams = 16;
TermKeyCsiParam params[16];
unsigned long cmd;
unsigned cmd;
TermKeyResult ret = parse_csi(tk, introlen, &csi_len, params, &nparams, &cmd);
if(ret == TERMKEY_RES_AGAIN) {
if(!force)
if (ret == TERMKEY_RES_AGAIN) {
if (!force) {
return TERMKEY_RES_AGAIN;
}
(*tk->method.emit_codepoint)(tk, '[', key);
key->modifiers |= TERMKEY_KEYMOD_ALT;
@ -678,7 +695,7 @@ static TermKeyResult peekkey_csi(TermKey *tk, TermKeyCsi *csi, size_t introlen,
return TERMKEY_RES_KEY;
}
if(cmd == 'M' && nparams < 3) { // Mouse in X10 encoding consumes the next 3 bytes also
if (cmd == 'M' && nparams < 3) { // Mouse in X10 encoding consumes the next 3 bytes also
tk->buffstart += csi_len;
tk->buffcount -= csi_len;
@ -687,8 +704,9 @@ static TermKeyResult peekkey_csi(TermKey *tk, TermKeyCsi *csi, size_t introlen,
tk->buffstart -= csi_len;
tk->buffcount += csi_len;
if(mouse_result == TERMKEY_RES_KEY)
if (mouse_result == TERMKEY_RES_KEY) {
*nbytep += csi_len;
}
return mouse_result;
}
@ -696,12 +714,13 @@ static TermKeyResult peekkey_csi(TermKey *tk, TermKeyCsi *csi, size_t introlen,
TermKeyResult result = TERMKEY_RES_NONE;
// We know from the logic above that cmd must be >= 0x40 and < 0x80
if(csi_handlers[(cmd & 0xff) - 0x40])
result = (*csi_handlers[(cmd & 0xff) - 0x40])(tk, key, cmd, params, nparams);
if (csi_handlers[(cmd & 0xff) - 0x40]) {
result = (*csi_handlers[(cmd & 0xff) - 0x40])(tk, key, (int)cmd, params, (int)nparams);
}
if(result == TERMKEY_RES_NONE) {
if (result == TERMKEY_RES_NONE) {
#ifdef DEBUG
switch(args) {
switch (args) {
case 0:
fprintf(stderr, "CSI: Unknown cmd=%c\n", (char)cmd);
break;
@ -712,15 +731,17 @@ static TermKeyResult peekkey_csi(TermKey *tk, TermKeyCsi *csi, size_t introlen,
fprintf(stderr, "CSI: Unknown arg1=%ld arg2=%ld cmd=%c\n", arg[0], arg[1], (char)cmd);
break;
case 3:
fprintf(stderr, "CSI: Unknown arg1=%ld arg2=%ld arg3=%ld cmd=%c\n", arg[0], arg[1], arg[2], (char)cmd);
fprintf(stderr, "CSI: Unknown arg1=%ld arg2=%ld arg3=%ld cmd=%c\n", arg[0], arg[1], arg[2],
(char)cmd);
break;
default:
fprintf(stderr, "CSI: Unknown arg1=%ld arg2=%ld arg3=%ld ... args=%d cmd=%c\n", arg[0], arg[1], arg[2], args, (char)cmd);
fprintf(stderr, "CSI: Unknown arg1=%ld arg2=%ld arg3=%ld ... args=%d cmd=%c\n", arg[0],
arg[1], arg[2], args, (char)cmd);
break;
}
#endif
key->type = TERMKEY_TYPE_UNKNOWN_CSI;
key->code.number = cmd;
key->code.number = (int)cmd;
key->modifiers = 0;
tk->hightide = csi_len - introlen;
@ -732,11 +753,13 @@ static TermKeyResult peekkey_csi(TermKey *tk, TermKeyCsi *csi, size_t introlen,
return result;
}
static TermKeyResult peekkey_ss3(TermKey *tk, TermKeyCsi *csi, size_t introlen, TermKeyKey *key, int force, size_t *nbytep)
static TermKeyResult peekkey_ss3(TermKey *tk, TermKeyCsi *csi, size_t introlen, TermKeyKey *key,
int force, size_t *nbytep)
{
if(tk->buffcount < introlen + 1) {
if(!force)
if (tk->buffcount < introlen + 1) {
if (!force) {
return TERMKEY_RES_AGAIN;
}
(*tk->method.emit_codepoint)(tk, 'O', key);
key->modifiers |= TERMKEY_KEYMOD_ALT;
@ -746,30 +769,30 @@ static TermKeyResult peekkey_ss3(TermKey *tk, TermKeyCsi *csi, size_t introlen,
unsigned char cmd = CHARAT(introlen);
if(cmd < 0x40 || cmd >= 0x80)
if (cmd < 0x40 || cmd >= 0x80) {
return TERMKEY_RES_NONE;
}
key->type = csi_ss3s[cmd - 0x40].type;
key->code.sym = csi_ss3s[cmd - 0x40].sym;
key->modifiers = csi_ss3s[cmd - 0x40].modifier_set;
if(key->code.sym == TERMKEY_SYM_UNKNOWN) {
if(tk->flags & TERMKEY_FLAG_CONVERTKP && ss3_kpalts[cmd - 0x40]) {
if (key->code.sym == TERMKEY_SYM_UNKNOWN) {
if (tk->flags & TERMKEY_FLAG_CONVERTKP && ss3_kpalts[cmd - 0x40]) {
key->type = TERMKEY_TYPE_UNICODE;
key->code.codepoint = ss3_kpalts[cmd - 0x40];
key->code.codepoint = (unsigned char)ss3_kpalts[cmd - 0x40];
key->modifiers = 0;
key->utf8[0] = key->code.codepoint;
key->utf8[0] = (char)key->code.codepoint;
key->utf8[1] = 0;
}
else {
} else {
key->type = ss3s[cmd - 0x40].type;
key->code.sym = ss3s[cmd - 0x40].sym;
key->modifiers = ss3s[cmd - 0x40].modifier_set;
}
}
if(key->code.sym == TERMKEY_SYM_UNKNOWN) {
if (key->code.sym == TERMKEY_SYM_UNKNOWN) {
#ifdef DEBUG
fprintf(stderr, "CSI: Unknown SS3 %c (0x%02x)\n", (char)cmd, cmd);
#endif
@ -781,25 +804,30 @@ static TermKeyResult peekkey_ss3(TermKey *tk, TermKeyCsi *csi, size_t introlen,
return TERMKEY_RES_KEY;
}
static TermKeyResult peekkey_ctrlstring(TermKey *tk, TermKeyCsi *csi, size_t introlen, TermKeyKey *key, int force, size_t *nbytep)
static TermKeyResult peekkey_ctrlstring(TermKey *tk, TermKeyCsi *csi, size_t introlen,
TermKeyKey *key, int force, size_t *nbytep)
{
size_t str_end = introlen;
while(str_end < tk->buffcount) {
if(CHARAT(str_end) == 0x07) // BEL
while (str_end < tk->buffcount) {
if (CHARAT(str_end) == 0x07) { // BEL
break;
if(CHARAT(str_end) == 0x9c) // ST
}
if (CHARAT(str_end) == 0x9c) { // ST
break;
if(CHARAT(str_end) == 0x1b &&
(str_end + 1) < tk->buffcount &&
CHARAT(str_end+1) == 0x5c) // ESC-prefixed ST
}
if (CHARAT(str_end) == 0x1b
&& (str_end + 1) < tk->buffcount
&& CHARAT(str_end + 1) == 0x5c) { // ESC-prefixed ST
break;
}
str_end++;
}
if(str_end >= tk->buffcount)
if (str_end >= tk->buffcount) {
return TERMKEY_RES_AGAIN;
}
#ifdef DEBUG
fprintf(stderr, "Found a control string: %*s",
@ -807,41 +835,45 @@ static TermKeyResult peekkey_ctrlstring(TermKey *tk, TermKeyCsi *csi, size_t int
#endif
*nbytep = str_end + 1;
if(CHARAT(str_end) == 0x1b)
if (CHARAT(str_end) == 0x1b) {
(*nbytep)++;
}
if(csi->saved_string)
free(csi->saved_string);
if (csi->saved_string) {
xfree(csi->saved_string);
}
size_t len = str_end - introlen;
csi->saved_string_id++;
csi->saved_string = malloc(len + 1);
csi->saved_string = xmalloc(len + 1);
strncpy(csi->saved_string, (char *)tk->buffer + tk->buffstart + introlen, len);
strncpy(csi->saved_string, (char *)tk->buffer + tk->buffstart + introlen, len); // NOLINT(runtime/printf)
csi->saved_string[len] = 0;
key->type = (CHARAT(introlen-1) & 0x1f) == 0x10 ?
TERMKEY_TYPE_DCS : TERMKEY_TYPE_OSC;
key->type = (CHARAT(introlen - 1) & 0x1f) == 0x10
? TERMKEY_TYPE_DCS : TERMKEY_TYPE_OSC;
key->code.number = csi->saved_string_id;
key->modifiers = 0;
return TERMKEY_RES_KEY;
}
static TermKeyResult peekkey(TermKey *tk, void *info, TermKeyKey *key, int force, size_t *nbytep)
TermKeyResult peekkey_csi(TermKey *tk, void *info, TermKeyKey *key, int force, size_t *nbytep)
{
if(tk->buffcount == 0)
if (tk->buffcount == 0) {
return tk->is_closed ? TERMKEY_RES_EOF : TERMKEY_RES_NONE;
}
TermKeyCsi *csi = info;
switch(CHARAT(0)) {
switch (CHARAT(0)) {
case 0x1b:
if(tk->buffcount < 2)
if (tk->buffcount < 2) {
return TERMKEY_RES_NONE;
}
switch(CHARAT(1)) {
switch (CHARAT(1)) {
case 0x4f: // ESC-prefixed SS3
return peekkey_ss3(tk, csi, 2, key, force, nbytep);
@ -850,7 +882,7 @@ static TermKeyResult peekkey(TermKey *tk, void *info, TermKeyKey *key, int force
return peekkey_ctrlstring(tk, csi, 2, key, force, nbytep);
case 0x5b: // ESC-prefixed CSI
return peekkey_csi(tk, csi, 2, key, force, nbytep);
return peekkey_csi_csi(tk, csi, 2, key, force, nbytep);
}
return TERMKEY_RES_NONE;
@ -863,41 +895,8 @@ static TermKeyResult peekkey(TermKey *tk, void *info, TermKeyKey *key, int force
return peekkey_ctrlstring(tk, csi, 1, key, force, nbytep);
case 0x9b: // CSI
return peekkey_csi(tk, csi, 1, key, force, nbytep);
return peekkey_csi_csi(tk, csi, 1, key, force, nbytep);
}
return TERMKEY_RES_NONE;
}
struct TermKeyDriver termkey_driver_csi = {
.name = "CSI",
.new_driver = new_driver,
.free_driver = free_driver,
.peekkey = peekkey,
};
TermKeyResult termkey_interpret_string(TermKey *tk, const TermKeyKey *key, const char **strp)
{
struct TermKeyDriverNode *p;
for(p = tk->drivers; p; p = p->next)
if(p->driver == &termkey_driver_csi)
break;
if(!p)
return TERMKEY_RES_NONE;
if(key->type != TERMKEY_TYPE_DCS &&
key->type != TERMKEY_TYPE_OSC)
return TERMKEY_RES_NONE;
TermKeyCsi *csi = p->info;
if(csi->saved_string_id != key->code.number)
return TERMKEY_RES_NONE;
*strp = csi->saved_string;
return TERMKEY_RES_KEY;
}

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 },
@ -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,32 +119,15 @@ 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;
@ -159,36 +136,35 @@ static struct trie_node *new_node_key(TermKeyType type, TermKeySym sym, int modm
n->key.modifier_mask = modmask;
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)
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];
}
}
@ -198,52 +174,54 @@ static struct trie_node *lookup_next(struct trie_node *n, unsigned char b)
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;
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])
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) {
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--)
;
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]) {
xfree(nar);
return new_node_arr(1, 0);
}
}
struct trie_node_arr *new = (struct trie_node_arr*)new_node_arr(min, max);
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++)
for (i = min; i <= max; i++) {
new->arr[i - min] = compress_trie(nar->arr[i]);
}
free(nar);
return (struct trie_node*)new;
xfree(nar);
return (struct trie_node *)new;
}
}
@ -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,39 +255,29 @@ 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){
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,
@ -319,247 +286,226 @@ static int load_terminfo(TermKeyTI *ti)
});
}
/* 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){
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,8 +514,9 @@ 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;
}
@ -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,32 +545,35 @@ 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",
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();
}
@ -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,26 +1,24 @@
#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
{
struct TermKeyDriver {
const char *name;
void *(*new_driver)(TermKey *tk, const char *term);
void (*free_driver)(void *info);
@ -51,8 +49,8 @@ struct TermKey {
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 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;
@ -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)
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 */