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. * 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/ * `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) * `runtime/lua/coxpcall.lua`: coxpcall (only needed for PUC lua, builtin to luajit)
* `src/termkey`: [libtermkey](https://github.com/neovim/libtermkey)
Other dependencies Other dependencies
-------------------------- --------------------------

View File

@ -54,8 +54,6 @@ if(ENABLE_WASMTIME)
target_compile_definitions(nvim_bin PRIVATE HAVE_WASMTIME) target_compile_definitions(nvim_bin PRIVATE HAVE_WASMTIME)
endif() endif()
target_compile_definitions(main_lib INTERFACE HAVE_UNIBILIUM)
# The unit test lib requires LuaJIT; it will be skipped if LuaJIT is missing. # 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) option(PREFER_LUA "Prefer Lua over LuaJIT in the nvim executable." OFF)
if(PREFER_LUA) if(PREFER_LUA)
@ -153,7 +151,7 @@ if(UNIX)
endif() endif()
if(CMAKE_SYSTEM_NAME MATCHES "Windows") 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) target_link_libraries(main_lib INTERFACE netapi32)
elseif(CMAKE_SYSTEM_NAME MATCHES "Darwin") elseif(CMAKE_SYSTEM_NAME MATCHES "Darwin")
target_link_libraries(nvim_bin PRIVATE "-framework CoreServices") 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_SOURCES CONFIGURE_DEPENDS *.c)
file(GLOB NVIM_HEADERS CONFIGURE_DEPENDS *.h) 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_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 ../termkey/*.h ../vterm/*.h) file(GLOB EXTERNAL_HEADERS CONFIGURE_DEPENDS ../xdiff/*.h ../mpack/*.h ../cjson/*.h ../klib/*.h ../vterm/*.h)
file(GLOB NLUA0_SOURCES CONFIGURE_DEPENDS ../mpack/*.c) file(GLOB NLUA0_SOURCES CONFIGURE_DEPENDS ../mpack/*.c)
@ -378,6 +376,15 @@ if(PREFER_LUA)
target_compile_definitions(main_lib INTERFACE NVIM_VENDOR_BIT) target_compile_definitions(main_lib INTERFACE NVIM_VENDOR_BIT)
endif() 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) list(APPEND NLUA0_SOURCES ${PROJECT_SOURCE_DIR}/src/nlua0.c)
foreach(subdir foreach(subdir
@ -386,6 +393,7 @@ foreach(subdir
api/private api/private
msgpack_rpc msgpack_rpc
tui tui
tui/termkey
event event
eval eval
lua lua
@ -407,49 +415,36 @@ endforeach()
list(SORT NVIM_SOURCES) list(SORT NVIM_SOURCES)
list(SORT NVIM_HEADERS) list(SORT NVIM_HEADERS)
list(APPEND LINT_NVIM_SOURCES ${NVIM_SOURCES} ${NVIM_HEADERS})
foreach(sfile ${NVIM_SOURCES}) foreach(sfile ${NVIM_SOURCES})
get_filename_component(f ${sfile} NAME) get_filename_component(f ${sfile} NAME)
if(WIN32 AND ${f} MATCHES "^(pty_process_unix.c)$") if(WIN32 AND ${f} MATCHES "^(pty_process_unix.c)$")
list(APPEND to_remove ${sfile}) list(REMOVE_ITEM NVIM_SOURCES ${sfile})
endif() endif()
if(NOT WIN32 AND ${f} MATCHES "^(pty_process_win.c)$") if(NOT WIN32 AND ${f} MATCHES "^(pty_process_win.c)$")
list(APPEND to_remove ${sfile}) list(REMOVE_ITEM NVIM_SOURCES ${sfile})
endif() endif()
if(NOT WIN32 AND ${f} MATCHES "^(pty_conpty_win.c)$") if(NOT WIN32 AND ${f} MATCHES "^(pty_conpty_win.c)$")
list(APPEND to_remove ${sfile}) list(REMOVE_ITEM NVIM_SOURCES ${sfile})
endif() endif()
if(NOT WIN32 AND ${f} MATCHES "^(os_win_console.c)$") if(NOT WIN32 AND ${f} MATCHES "^(os_win_console.c)$")
list(APPEND to_remove ${sfile}) list(REMOVE_ITEM NVIM_SOURCES ${sfile})
endif() endif()
endforeach() endforeach()
list(REMOVE_ITEM NVIM_SOURCES ${to_remove})
foreach(hfile ${NVIM_HEADERS}) foreach(hfile ${NVIM_HEADERS})
get_filename_component(f ${hfile} NAME) get_filename_component(f ${hfile} NAME)
if(WIN32 AND ${f} MATCHES "^(unix_defs.h)$") if(WIN32 AND ${f} MATCHES "^(unix_defs.h)$")
list(APPEND to_remove_h ${hfile}) list(REMOVE_ITEM NVIM_HEADERS ${hfile})
endif() endif()
if(WIN32 AND ${f} MATCHES "^(pty_process_unix.h)$") if(WIN32 AND ${f} MATCHES "^(pty_process_unix.h)$")
list(APPEND to_remove_h ${hfile}) list(REMOVE_ITEM NVIM_HEADERS ${hfile})
endif() endif()
if(NOT WIN32 AND ${f} MATCHES "^(win_defs.h)$") if(NOT WIN32 AND ${f} MATCHES "^(win_defs.h)$")
list(APPEND to_remove_h ${hfile}) list(REMOVE_ITEM NVIM_HEADERS ${hfile})
endif() endif()
endforeach() endforeach()
list(REMOVE_ITEM NVIM_HEADERS ${to_remove_h}) list(APPEND LINT_NVIM_SOURCES ${NVIM_SOURCES} ${NVIM_HEADERS})
# 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()
# Log level (NVIM_LOG_DEBUG in log.h) # Log level (NVIM_LOG_DEBUG in log.h)
if(CI_BUILD) if(CI_BUILD)
@ -849,7 +844,7 @@ endif()
add_glob_target( add_glob_target(
TARGET lintc-clang-tidy TARGET lintc-clang-tidy
COMMAND ${CLANG_TIDY_PRG} COMMAND ${CLANG_TIDY_PRG}
FILES ${NVIM_SOURCES} ${NVIM_HEADERS} FILES ${LINT_NVIM_SOURCES}
FLAGS --quiet FLAGS --quiet
EXCLUDE ${EXCLUDE_CLANG_TIDY}) EXCLUDE ${EXCLUDE_CLANG_TIDY})
@ -862,7 +857,7 @@ endif()
add_glob_target( add_glob_target(
TARGET clang-analyzer TARGET clang-analyzer
COMMAND ${CLANG_TIDY_PRG} COMMAND ${CLANG_TIDY_PRG}
FILES ${NVIM_SOURCES} ${NVIM_HEADERS} FILES ${LINT_NVIM_SOURCES}
FLAGS --quiet FLAGS --quiet
--checks=' --checks='
-*, -*,
@ -905,13 +900,13 @@ add_glob_target(
TARGET lintc-uncrustify TARGET lintc-uncrustify
COMMAND ${UNCRUSTIFY_PRG} COMMAND ${UNCRUSTIFY_PRG}
FLAGS -c ${UNCRUSTIFY_CONFIG} -q --check FLAGS -c ${UNCRUSTIFY_CONFIG} -q --check
FILES ${LINT_NVIM_SOURCES}) FILES ${NVIM_SOURCES} ${NVIM_HEADERS})
add_glob_target( add_glob_target(
TARGET formatc TARGET formatc
COMMAND ${UNCRUSTIFY_PRG} COMMAND ${UNCRUSTIFY_PRG}
FLAGS -c ${UNCRUSTIFY_CONFIG} --replace --no-backup 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(lintc-uncrustify uncrustify_update_config)
add_dependencies(formatc uncrustify_update_config) add_dependencies(formatc uncrustify_update_config)

View File

@ -16,9 +16,6 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <windows.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 // Windows does not have S_IFLNK but libuv defines it
// and sets the flag for us when calling uv_fs_stat. // and sets the flag for us when calling uv_fs_stat.
#include <uv.h> #include <uv.h>

View File

@ -7,24 +7,27 @@
#include "nvim/api/private/defs.h" #include "nvim/api/private/defs.h"
#include "nvim/api/private/helpers.h" #include "nvim/api/private/helpers.h"
#include "nvim/event/loop.h" #include "nvim/event/loop.h"
#include "nvim/event/rstream.h"
#include "nvim/event/stream.h" #include "nvim/event/stream.h"
#include "nvim/macros_defs.h" #include "nvim/macros_defs.h"
#include "nvim/main.h" #include "nvim/main.h"
#include "nvim/map_defs.h" #include "nvim/map_defs.h"
#include "nvim/memory.h" #include "nvim/memory.h"
#include "nvim/msgpack_rpc/channel.h"
#include "nvim/option_vars.h" #include "nvim/option_vars.h"
#include "nvim/os/os.h" #include "nvim/os/os.h"
#include "nvim/os/os_defs.h" #include "nvim/os/os_defs.h"
#include "nvim/strings.h" #include "nvim/strings.h"
#include "nvim/tui/input.h" #include "nvim/tui/input.h"
#include "nvim/tui/input_defs.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/tui/tui.h"
#include "nvim/ui_client.h" #include "nvim/ui_client.h"
#ifdef MSWIN #ifdef MSWIN
# include "nvim/os/os_win_console.h" # include "nvim/os/os_win_console.h"
#endif #endif
#include "nvim/event/rstream.h"
#include "nvim/msgpack_rpc/channel.h"
#define READ_STREAM_SIZE 0xfff #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) 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) { if (name) {
char buf[64]; char buf[64];
size_t len = 0; 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 // contain, so just allocate enough space for a large upper bound
TermKeyCsiParam params[16]; TermKeyCsiParam params[16];
size_t nparams = 16; size_t nparams = 16;
unsigned long cmd; unsigned cmd;
if (termkey_interpret_csi(input->tk, key, params, &nparams, &cmd) != TERMKEY_RES_KEY) { if (termkey_interpret_csi(input->tk, key, params, &nparams, &cmd) != TERMKEY_RES_KEY) {
return; return;
} }
@ -641,7 +644,7 @@ static void handle_unknown_csi(TermInput *input, const TermKeyKey *key)
case 't': case 't':
if (nparams == 5) { if (nparams == 5) {
// We only care about the first 3 parameters, and we ignore subparameters // 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++) { for (size_t i = 0; i < ARRAY_SIZE(args); i++) {
if (termkey_interpret_csi_param(params[i], &args[i], NULL, NULL) != TERMKEY_RES_KEY) { if (termkey_interpret_csi_param(params[i], &args[i], NULL, NULL) != TERMKEY_RES_KEY) {
return; return;
@ -650,8 +653,8 @@ static void handle_unknown_csi(TermInput *input, const TermKeyKey *key)
if (args[0] == 48) { if (args[0] == 48) {
// In-band resize event (DEC private mode 2048) // In-band resize event (DEC private mode 2048)
int height_chars = (int)args[1]; int height_chars = args[1];
int width_chars = (int)args[2]; int width_chars = args[2];
tui_set_size(input->tui_data, width_chars, height_chars); tui_set_size(input->tui_data, width_chars, height_chars);
ui_client_set_size(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/event/defs.h"
#include "nvim/tui/input_defs.h" // IWYU pragma: keep #include "nvim/tui/input_defs.h" // IWYU pragma: keep
#include "nvim/tui/termkey/termkey_defs.h"
#include "nvim/tui/tui_defs.h" #include "nvim/tui/tui_defs.h"
#include "nvim/types_defs.h" #include "nvim/types_defs.h"
#include "termkey/termkey.h"
typedef enum { typedef enum {
kKeyEncodingLegacy, ///< Legacy key encoding 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 <assert.h>
#include <stdio.h> #include <stdio.h>
#include <string.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 // There are 64 codes 0x40 - 0x7F
static int keyinfo_initialised = 0; static int keyinfo_initialised = 0;
static struct keyinfo ss3s[64]; static struct keyinfo ss3s[64];
static char ss3_kpalts[64]; static char ss3_kpalts[64];
typedef struct { typedef TermKeyResult CsiHandler(TermKey *tk, TermKeyKey *key, int cmd, TermKeyCsiParam *params,
TermKey *tk; int nparams);
int saved_string_id;
char *saved_string;
} TermKeyCsi;
typedef TermKeyResult CsiHandler(TermKey *tk, TermKeyKey *key, int cmd, TermKeyCsiParam *params, int nparams);
static CsiHandler *csi_handlers[64]; static CsiHandler *csi_handlers[64];
/* // Handler for CSI/SS3 cmd keys
* Handler for CSI/SS3 cmd keys
*/
static struct keyinfo csi_ss3s[64]; 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; TermKeyResult result = TERMKEY_RES_KEY;
if (nparams > 1 && params[1].param != NULL) { if (nparams > 1 && params[1].param != NULL) {
long arg = 0; int arg = 0;
result = termkey_interpret_csi_param(params[1], &arg, NULL, NULL); result = termkey_interpret_csi_param(params[1], &arg, NULL, NULL);
if (result != TERMKEY_RES_KEY) { if (result != TERMKEY_RES_KEY) {
return result; return result;
@ -46,13 +47,15 @@ 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_mask);
key->modifiers |= csi_ss3s[cmd - 0x40].modifier_set; 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; result = TERMKEY_RES_NONE;
}
return result; 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; return;
@ -71,10 +74,7 @@ static void register_csi_ss3(TermKeyType type, TermKeySym sym, unsigned char cmd
register_csi_ss3_full(type, sym, 0, 0, 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) static void register_ss3kpalt(TermKeyType type, TermKeySym sym, unsigned char cmd, char kpalt)
{ {
if (cmd < 0x40 || cmd >= 0x80) { if (cmd < 0x40 || cmd >= 0x80) {
@ -88,21 +88,20 @@ static void register_ss3kpalt(TermKeyType type, TermKeySym sym, unsigned char cm
ss3_kpalts[cmd - 0x40] = kpalt; 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 35 // This value must be increased if more CSI function keys are added
#define NCSIFUNCS (sizeof(csifuncs)/sizeof(csifuncs[0])) 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) { if (nparams == 0) {
return TERMKEY_RES_NONE; return TERMKEY_RES_NONE;
} }
TermKeyResult result = TERMKEY_RES_KEY; 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); result = termkey_interpret_csi_param(params[1], &args[1], NULL, NULL);
@ -131,15 +130,14 @@ static TermKeyResult handle_csifunc(TermKey *tk, TermKeyKey *key, int cmd, TermK
int mod = key->modifiers; int mod = key->modifiers;
(*tk->method.emit_codepoint)(tk, args[2], key); (*tk->method.emit_codepoint)(tk, args[2], key);
key->modifiers |= mod; 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->type = csifuncs[args[0]].type;
key->code.sym = csifuncs[args[0]].sym; key->code.sym = csifuncs[args[0]].sym;
key->modifiers &= ~(csifuncs[args[0]].modifier_mask); key->modifiers &= ~(csifuncs[args[0]].modifier_mask);
key->modifiers |= csifuncs[args[0]].modifier_set; key->modifiers |= csifuncs[args[0]].modifier_set;
} } else {
else
key->code.sym = TERMKEY_SYM_UNKNOWN; key->code.sym = TERMKEY_SYM_UNKNOWN;
}
if (key->code.sym == TERMKEY_SYM_UNKNOWN) { if (key->code.sym == TERMKEY_SYM_UNKNOWN) {
#ifdef DEBUG #ifdef DEBUG
@ -165,19 +163,18 @@ static void register_csifunc(TermKeyType type, TermKeySym sym, int number)
csi_handlers['~' - 0x40] = &handle_csifunc; csi_handlers['~' - 0x40] = &handle_csifunc;
} }
/* /// Handler for CSI u extended Unicode keys
* Handler for CSI u extended Unicode keys static TermKeyResult handle_csi_u(TermKey *tk, TermKeyKey *key, int cmd, TermKeyCsiParam *params,
*/ int nparams)
static TermKeyResult handle_csi_u(TermKey *tk, TermKeyKey *key, int cmd, TermKeyCsiParam *params, int nparams)
{ {
switch (cmd) { switch (cmd) {
case 'u': { case 'u': {
long args[2]; int args[2];
if (nparams > 1 && params[1].param != NULL) { if (nparams > 1 && params[1].param != NULL) {
long subparam = 0; int subparam = 0;
size_t nsubparams = 1; 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; return TERMKEY_RES_ERROR;
} }
@ -207,12 +204,10 @@ 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
* Handler for CSI M / CSI m mouse events in SGR and rxvt encodings /// Note: This does not handle X10 encoding
* Note: This does not handle X10 encoding static TermKeyResult handle_csi_m(TermKey *tk, TermKeyKey *key, int cmd, TermKeyCsiParam *params,
*/ int nparams)
static TermKeyResult handle_csi_m(TermKey *tk, TermKeyKey *key, int cmd, TermKeyCsiParam *params, int nparams)
{ {
int initial = cmd >> 8; int initial = cmd >> 8;
cmd &= 0xff; cmd &= 0xff;
@ -229,7 +224,7 @@ static TermKeyResult handle_csi_m(TermKey *tk, TermKeyKey *key, int cmd, TermKey
return TERMKEY_RES_NONE; return TERMKEY_RES_NONE;
} }
long args[3]; int args[3];
for (size_t i = 0; i < 3; i++) { for (size_t i = 0; i < 3; i++) {
if (termkey_interpret_csi_param(params[i], &args[i], NULL, NULL) != TERMKEY_RES_KEY) { if (termkey_interpret_csi_param(params[i], &args[i], NULL, NULL) != TERMKEY_RES_KEY) {
return TERMKEY_RES_ERROR; return TERMKEY_RES_ERROR;
@ -238,7 +233,7 @@ static TermKeyResult handle_csi_m(TermKey *tk, TermKeyKey *key, int cmd, TermKey
if (!initial) { // rxvt protocol if (!initial) { // rxvt protocol
key->type = TERMKEY_TYPE_MOUSE; 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->modifiers = (key->code.mouse[0] & 0x1c) >> 2;
key->code.mouse[0] &= ~0x1c; key->code.mouse[0] &= ~0x1c;
@ -250,15 +245,16 @@ static TermKeyResult handle_csi_m(TermKey *tk, TermKeyKey *key, int cmd, TermKey
if (initial == '<') { // SGR protocol if (initial == '<') { // SGR protocol
key->type = TERMKEY_TYPE_MOUSE; 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->modifiers = (key->code.mouse[0] & 0x1c) >> 2;
key->code.mouse[0] &= ~0x1c; key->code.mouse[0] &= ~0x1c;
termkey_key_set_linecol(key, args[1], args[2]); termkey_key_set_linecol(key, args[1], args[2]);
if(cmd == 'm') // release if (cmd == 'm') { // release
key->code.mouse[3] |= 0x80; key->code.mouse[3] |= 0x80;
}
return TERMKEY_RES_KEY; return TERMKEY_RES_KEY;
} }
@ -266,22 +262,26 @@ static TermKeyResult handle_csi_m(TermKey *tk, TermKeyKey *key, int cmd, TermKey
return TERMKEY_RES_NONE; 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; return TERMKEY_RES_NONE;
}
if(button) if (button) {
*button = 0; *button = 0;
}
termkey_key_get_linecol(key, line, col); termkey_key_get_linecol(key, line, col);
if(!event) if (!event) {
return TERMKEY_RES_KEY; return TERMKEY_RES_KEY;
}
int btn = 0; int btn = 0;
int code = key->code.mouse[0]; int code = (unsigned char)key->code.mouse[0];
int drag = code & 0x20; int drag = code & 0x20;
@ -312,28 +312,29 @@ TermKeyResult termkey_interpret_mouse(TermKey *tk, const TermKeyKey *key, TermKe
*event = TERMKEY_MOUSE_UNKNOWN; *event = TERMKEY_MOUSE_UNKNOWN;
} }
if(button) if (button) {
*button = btn; *button = btn;
}
if(key->code.mouse[3] & 0x80) if (key->code.mouse[3] & 0x80) {
*event = TERMKEY_MOUSE_RELEASE; *event = TERMKEY_MOUSE_RELEASE;
}
return TERMKEY_RES_KEY; return TERMKEY_RES_KEY;
} }
/* /// Handler for CSI ? R position reports
* Handler for CSI ? R position reports /// A plain CSI R with no arguments is probably actually <F3>
* 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)
static TermKeyResult handle_csi_R(TermKey *tk, TermKeyKey *key, int cmd, TermKeyCsiParam *params, int nparams)
{ {
switch (cmd) { switch (cmd) {
case 'R'|'?' << 8: case 'R'|'?' << 8:
if(nparams < 2) if (nparams < 2) {
return TERMKEY_RES_NONE; return TERMKEY_RES_NONE;
}
long args[2]; int args[2];
if (termkey_interpret_csi_param(params[0], &args[0], NULL, NULL) != TERMKEY_RES_KEY) { if (termkey_interpret_csi_param(params[0], &args[0], NULL, NULL) != TERMKEY_RES_KEY) {
return TERMKEY_RES_ERROR; 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) 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; return TERMKEY_RES_NONE;
}
termkey_key_get_linecol(key, line, col); termkey_key_get_linecol(key, line, col);
return TERMKEY_RES_KEY; return TERMKEY_RES_KEY;
} }
/* /// Handler for CSI $y mode status reports
* Handler for CSI $y mode status reports static TermKeyResult handle_csi_y(TermKey *tk, TermKeyKey *key, int cmd, TermKeyCsiParam *params,
*/ int nparams)
static TermKeyResult handle_csi_y(TermKey *tk, TermKeyKey *key, int cmd, TermKeyCsiParam *params, int nparams)
{ {
switch (cmd) { switch (cmd) {
case 'y'|'$' << 16: case 'y'|'$' << 16:
case 'y'|'$' << 16 | '?' << 8: case 'y'|'$' << 16 | '?' << 8:
if(nparams < 2) if (nparams < 2) {
return TERMKEY_RES_NONE; return TERMKEY_RES_NONE;
}
long args[2]; int args[2];
if (termkey_interpret_csi_param(params[0], &args[0], NULL, NULL) != TERMKEY_RES_KEY) { if (termkey_interpret_csi_param(params[0], &args[0], NULL, NULL) != TERMKEY_RES_KEY) {
return TERMKEY_RES_ERROR; 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->type = TERMKEY_TYPE_MODEREPORT;
key->code.mouse[0] = (cmd >> 8); key->code.mouse[0] = (char)(cmd >> 8);
key->code.mouse[1] = args[0] >> 8; key->code.mouse[1] = (char)(args[0] >> 8);
key->code.mouse[2] = args[0] & 0xff; key->code.mouse[2] = (char)(args[0] & 0xff);
key->code.mouse[3] = args[1]; key->code.mouse[3] = (char)args[1];
return TERMKEY_RES_KEY; return TERMKEY_RES_KEY;
default: 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; return TERMKEY_RES_NONE;
}
if(initial) if (initial) {
*initial = key->code.mouse[0]; *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]; *mode = ((uint8_t)key->code.mouse[1] << 8) | (uint8_t)key->code.mouse[2];
}
if(value) if (value) {
*value = key->code.mouse[3]; *value = (unsigned char)key->code.mouse[3];
}
return TERMKEY_RES_KEY; return TERMKEY_RES_KEY;
} }
#define CHARAT(i) (tk->buffer[tk->buffstart + (i)]) #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; size_t csi_end = introlen;
while (csi_end < tk->buffcount) { while (csi_end < tk->buffcount) {
if(CHARAT(csi_end) >= 0x40 && CHARAT(csi_end) < 0x80) if (CHARAT(csi_end) >= 0x40 && CHARAT(csi_end) < 0x80) {
break; break;
}
csi_end++; csi_end++;
} }
if(csi_end >= tk->buffcount) if (csi_end >= tk->buffcount) {
return TERMKEY_RES_AGAIN; return TERMKEY_RES_AGAIN;
}
unsigned char cmd = CHARAT(csi_end); unsigned char cmd = CHARAT(csi_end);
*commandp = cmd; *commandp = cmd;
@ -436,7 +445,7 @@ static TermKeyResult parse_csi(TermKey *tk, size_t introlen, size_t *csi_len, Te
// See if there is an initial byte // See if there is an initial byte
if (CHARAT(p) >= '<' && CHARAT(p) <= '?') { if (CHARAT(p) >= '<' && CHARAT(p) <= '?') {
*commandp |= (CHARAT(p) << 8); *commandp |= (unsigned)(CHARAT(p) << 8);
p++; p++;
} }
@ -449,22 +458,21 @@ static TermKeyResult parse_csi(TermKey *tk, size_t introlen, size_t *csi_len, Te
params[argi].param = &CHARAT(p); params[argi].param = &CHARAT(p);
present = 1; present = 1;
} }
} } else if (c == ';') {
else if(c == ';') {
if (!present) { if (!present) {
params[argi].param = NULL; params[argi].param = NULL;
params[argi].length = 0; params[argi].length = 0;
} else { } else {
params[argi].length = &CHARAT(p) - params[argi].param; params[argi].length = (size_t)(&CHARAT(p) - params[argi].param);
} }
present = 0; present = 0;
argi++; argi++;
if(argi > 16) if (argi > 16) {
break; break;
} }
else if(c >= 0x20 && c <= 0x2f) { } else if (c >= 0x20 && c <= 0x2f) {
*commandp |= c << 16; *commandp |= (unsigned)(c << 16);
break; break;
} }
@ -472,29 +480,33 @@ static TermKeyResult parse_csi(TermKey *tk, size_t introlen, size_t *csi_len, Te
} }
if (present) { if (present) {
params[argi].length = &CHARAT(p) - params[argi].param; params[argi].length = (size_t)(&CHARAT(p) - params[argi].param);
argi++; argi++;
} }
*nargs = argi; *nargs = (size_t)argi;
*csi_len = csi_end + 1; *csi_len = csi_end + 1;
return TERMKEY_RES_KEY; 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; size_t dummy;
if(tk->hightide == 0) if (tk->hightide == 0) {
return TERMKEY_RES_NONE; return TERMKEY_RES_NONE;
if(key->type != TERMKEY_TYPE_UNKNOWN_CSI) }
if (key->type != TERMKEY_TYPE_UNKNOWN_CSI) {
return TERMKEY_RES_NONE; return TERMKEY_RES_NONE;
}
return parse_csi(tk, 0, &dummy, params, nparams, cmd); 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) { if (paramp == NULL) {
return TERMKEY_RES_ERROR; return TERMKEY_RES_ERROR;
@ -508,7 +520,7 @@ TermKeyResult termkey_interpret_csi_param(TermKeyCsiParam param, long *paramp, l
return TERMKEY_RES_KEY; return TERMKEY_RES_KEY;
} }
long arg = 0; int arg = 0;
size_t i = 0; size_t i = 0;
size_t capacity = nsubparams ? *nsubparams : 0; size_t capacity = nsubparams ? *nsubparams : 0;
size_t length = 0; size_t length = 0;
@ -553,8 +565,9 @@ static int register_keys(void)
ss3_kpalts[i] = 0; ss3_kpalts[i] = 0;
} }
for(i = 0; i < NCSIFUNCS; i++) for (i = 0; i < NCSIFUNCS; i++) {
csifuncs[i].sym = TERMKEY_SYM_UNKNOWN; csifuncs[i].sym = TERMKEY_SYM_UNKNOWN;
}
register_csi_ss3(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_UP, 'A'); register_csi_ss3(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_UP, 'A');
register_csi_ss3(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_DOWN, 'B'); 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, 3, 'R');
register_csi_ss3(TERMKEY_TYPE_FUNCTION, 4, 'S'); 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_KPENTER, 'M', 0);
register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KPEQUALS, 'X', '='); register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KPEQUALS, 'X', '=');
@ -632,15 +646,15 @@ static int register_keys(void)
return 1; return 1;
} }
static void *new_driver(TermKey *tk, const char *term) void *new_driver_csi(TermKey *tk, const char *term)
{ {
if(!keyinfo_initialised) if (!keyinfo_initialised) {
if(!register_keys()) if (!register_keys()) {
return NULL; return NULL;
}
}
TermKeyCsi *csi = malloc(sizeof *csi); TermKeyCsi *csi = xmalloc(sizeof *csi);
if(!csi)
return NULL;
csi->tk = tk; csi->tk = tk;
csi->saved_string_id = 0; csi->saved_string_id = 0;
@ -649,28 +663,31 @@ static void *new_driver(TermKey *tk, const char *term)
return csi; return csi;
} }
static void free_driver(void *info) void free_driver_csi(void *info)
{ {
TermKeyCsi *csi = info; TermKeyCsi *csi = info;
if(csi->saved_string) if (csi->saved_string) {
free(csi->saved_string); xfree(csi->saved_string);
free(csi);
} }
static TermKeyResult peekkey_csi(TermKey *tk, TermKeyCsi *csi, size_t introlen, TermKeyKey *key, int force, size_t *nbytep) xfree(csi);
}
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 csi_len;
size_t nparams = 16; size_t nparams = 16;
TermKeyCsiParam params[16]; TermKeyCsiParam params[16];
unsigned long cmd; unsigned cmd;
TermKeyResult ret = parse_csi(tk, introlen, &csi_len, params, &nparams, &cmd); TermKeyResult ret = parse_csi(tk, introlen, &csi_len, params, &nparams, &cmd);
if (ret == TERMKEY_RES_AGAIN) { if (ret == TERMKEY_RES_AGAIN) {
if(!force) if (!force) {
return TERMKEY_RES_AGAIN; return TERMKEY_RES_AGAIN;
}
(*tk->method.emit_codepoint)(tk, '[', key); (*tk->method.emit_codepoint)(tk, '[', key);
key->modifiers |= TERMKEY_KEYMOD_ALT; key->modifiers |= TERMKEY_KEYMOD_ALT;
@ -687,8 +704,9 @@ static TermKeyResult peekkey_csi(TermKey *tk, TermKeyCsi *csi, size_t introlen,
tk->buffstart -= csi_len; tk->buffstart -= csi_len;
tk->buffcount += csi_len; tk->buffcount += csi_len;
if(mouse_result == TERMKEY_RES_KEY) if (mouse_result == TERMKEY_RES_KEY) {
*nbytep += csi_len; *nbytep += csi_len;
}
return mouse_result; return mouse_result;
} }
@ -696,8 +714,9 @@ static TermKeyResult peekkey_csi(TermKey *tk, TermKeyCsi *csi, size_t introlen,
TermKeyResult result = TERMKEY_RES_NONE; TermKeyResult result = TERMKEY_RES_NONE;
// We know from the logic above that cmd must be >= 0x40 and < 0x80 // We know from the logic above that cmd must be >= 0x40 and < 0x80
if(csi_handlers[(cmd & 0xff) - 0x40]) if (csi_handlers[(cmd & 0xff) - 0x40]) {
result = (*csi_handlers[(cmd & 0xff) - 0x40])(tk, key, cmd, params, nparams); 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 #ifdef DEBUG
@ -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); fprintf(stderr, "CSI: Unknown arg1=%ld arg2=%ld cmd=%c\n", arg[0], arg[1], (char)cmd);
break; break;
case 3: 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; break;
default: 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; break;
} }
#endif #endif
key->type = TERMKEY_TYPE_UNKNOWN_CSI; key->type = TERMKEY_TYPE_UNKNOWN_CSI;
key->code.number = cmd; key->code.number = (int)cmd;
key->modifiers = 0; key->modifiers = 0;
tk->hightide = csi_len - introlen; tk->hightide = csi_len - introlen;
@ -732,11 +753,13 @@ static TermKeyResult peekkey_csi(TermKey *tk, TermKeyCsi *csi, size_t introlen,
return result; 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 (tk->buffcount < introlen + 1) {
if(!force) if (!force) {
return TERMKEY_RES_AGAIN; return TERMKEY_RES_AGAIN;
}
(*tk->method.emit_codepoint)(tk, 'O', key); (*tk->method.emit_codepoint)(tk, 'O', key);
key->modifiers |= TERMKEY_KEYMOD_ALT; key->modifiers |= TERMKEY_KEYMOD_ALT;
@ -746,8 +769,9 @@ static TermKeyResult peekkey_ss3(TermKey *tk, TermKeyCsi *csi, size_t introlen,
unsigned char cmd = CHARAT(introlen); unsigned char cmd = CHARAT(introlen);
if(cmd < 0x40 || cmd >= 0x80) if (cmd < 0x40 || cmd >= 0x80) {
return TERMKEY_RES_NONE; return TERMKEY_RES_NONE;
}
key->type = csi_ss3s[cmd - 0x40].type; key->type = csi_ss3s[cmd - 0x40].type;
key->code.sym = csi_ss3s[cmd - 0x40].sym; key->code.sym = csi_ss3s[cmd - 0x40].sym;
@ -756,13 +780,12 @@ static TermKeyResult peekkey_ss3(TermKey *tk, TermKeyCsi *csi, size_t introlen,
if (key->code.sym == TERMKEY_SYM_UNKNOWN) { if (key->code.sym == TERMKEY_SYM_UNKNOWN) {
if (tk->flags & TERMKEY_FLAG_CONVERTKP && ss3_kpalts[cmd - 0x40]) { if (tk->flags & TERMKEY_FLAG_CONVERTKP && ss3_kpalts[cmd - 0x40]) {
key->type = TERMKEY_TYPE_UNICODE; 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->modifiers = 0;
key->utf8[0] = key->code.codepoint; key->utf8[0] = (char)key->code.codepoint;
key->utf8[1] = 0; key->utf8[1] = 0;
} } else {
else {
key->type = ss3s[cmd - 0x40].type; key->type = ss3s[cmd - 0x40].type;
key->code.sym = ss3s[cmd - 0x40].sym; key->code.sym = ss3s[cmd - 0x40].sym;
key->modifiers = ss3s[cmd - 0x40].modifier_set; key->modifiers = ss3s[cmd - 0x40].modifier_set;
@ -781,25 +804,30 @@ static TermKeyResult peekkey_ss3(TermKey *tk, TermKeyCsi *csi, size_t introlen,
return TERMKEY_RES_KEY; 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; size_t str_end = introlen;
while (str_end < tk->buffcount) { while (str_end < tk->buffcount) {
if(CHARAT(str_end) == 0x07) // BEL if (CHARAT(str_end) == 0x07) { // BEL
break; break;
if(CHARAT(str_end) == 0x9c) // ST }
if (CHARAT(str_end) == 0x9c) { // ST
break; break;
if(CHARAT(str_end) == 0x1b && }
(str_end + 1) < tk->buffcount && if (CHARAT(str_end) == 0x1b
CHARAT(str_end+1) == 0x5c) // ESC-prefixed ST && (str_end + 1) < tk->buffcount
&& CHARAT(str_end + 1) == 0x5c) { // ESC-prefixed ST
break; break;
}
str_end++; str_end++;
} }
if(str_end >= tk->buffcount) if (str_end >= tk->buffcount) {
return TERMKEY_RES_AGAIN; return TERMKEY_RES_AGAIN;
}
#ifdef DEBUG #ifdef DEBUG
fprintf(stderr, "Found a control string: %*s", fprintf(stderr, "Found a control string: %*s",
@ -807,39 +835,43 @@ static TermKeyResult peekkey_ctrlstring(TermKey *tk, TermKeyCsi *csi, size_t int
#endif #endif
*nbytep = str_end + 1; *nbytep = str_end + 1;
if(CHARAT(str_end) == 0x1b) if (CHARAT(str_end) == 0x1b) {
(*nbytep)++; (*nbytep)++;
}
if(csi->saved_string) if (csi->saved_string) {
free(csi->saved_string); xfree(csi->saved_string);
}
size_t len = str_end - introlen; size_t len = str_end - introlen;
csi->saved_string_id++; 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; csi->saved_string[len] = 0;
key->type = (CHARAT(introlen-1) & 0x1f) == 0x10 ? key->type = (CHARAT(introlen - 1) & 0x1f) == 0x10
TERMKEY_TYPE_DCS : TERMKEY_TYPE_OSC; ? TERMKEY_TYPE_DCS : TERMKEY_TYPE_OSC;
key->code.number = csi->saved_string_id; key->code.number = csi->saved_string_id;
key->modifiers = 0; key->modifiers = 0;
return TERMKEY_RES_KEY; 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; return tk->is_closed ? TERMKEY_RES_EOF : TERMKEY_RES_NONE;
}
TermKeyCsi *csi = info; TermKeyCsi *csi = info;
switch (CHARAT(0)) { switch (CHARAT(0)) {
case 0x1b: case 0x1b:
if(tk->buffcount < 2) if (tk->buffcount < 2) {
return TERMKEY_RES_NONE; return TERMKEY_RES_NONE;
}
switch (CHARAT(1)) { switch (CHARAT(1)) {
case 0x4f: // ESC-prefixed SS3 case 0x4f: // ESC-prefixed SS3
@ -850,7 +882,7 @@ static TermKeyResult peekkey(TermKey *tk, void *info, TermKeyKey *key, int force
return peekkey_ctrlstring(tk, csi, 2, key, force, nbytep); return peekkey_ctrlstring(tk, csi, 2, key, force, nbytep);
case 0x5b: // ESC-prefixed CSI 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; 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); return peekkey_ctrlstring(tk, csi, 1, key, force, nbytep);
case 0x9b: // CSI 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; 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,31 +1,26 @@
// 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 <ctype.h>
#include <errno.h> #include <errno.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdio.h> #include <stdio.h>
#include <string.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 #ifndef _WIN32
# include <unistd.h> # include <unistd.h>
#else #else
# include <io.h> # include <io.h>
#endif #endif
#include <sys/types.h>
#include <sys/stat.h> #ifdef INCLUDE_GENERATED_DECLARATIONS
# include "tui/termkey/driver-ti.c.generated.h"
#endif
#define streq(a, b) (!strcmp(a, b)) #define streq(a, b) (!strcmp(a, b))
@ -36,9 +31,8 @@ static struct {
TermKeyType type; TermKeyType type;
TermKeySym sym; TermKeySym sym;
int mods; int mods;
} funcs[] = } funcs[] = {
{ // THIS LIST MUST REMAIN SORTED!
/* THIS LIST MUST REMAIN SORTED! */
{ "backspace", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_BACKSPACE, 0 }, { "backspace", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_BACKSPACE, 0 },
{ "begin", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_BEGIN, 0 }, { "begin", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_BEGIN, 0 },
{ "beg", 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 }, { "suspend", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_SUSPEND, 0 },
{ "undo", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_UNDO, 0 }, { "undo", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_UNDO, 0 },
{ "up", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_UP, 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) static enum unibi_string unibi_lookup_str(const char *name)
{ {
for(enum unibi_string ret = unibi_string_begin_+1; ret < unibi_string_end_; ret++) for (enum unibi_string ret = unibi_string_begin_ + 1; ret < unibi_string_end_; ret++) {
if(streq(unibi_name_str(ret), name)) if (streq(unibi_name_str(ret), name)) {
return ret; return ret;
}
}
return -1; return (enum unibi_string)-1;
} }
static const char *unibi_get_str_by_name(const unibi_term *ut, const char *name) static const char *unibi_get_str_by_name(const unibi_term *ut, const char *name)
{ {
enum unibi_string idx = unibi_lookup_str(name); enum unibi_string idx = unibi_lookup_str(name);
if(idx == (enum unibi_string)-1) if (idx == (enum unibi_string)-1) {
return NULL; return NULL;
}
return unibi_get_str(ut, idx); return unibi_get_str(ut, idx);
} }
#endif
/* To be efficient at lookups, we store the byte sequence => keyinfo mapping // 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 // 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 // sequences. Because it is likely most nodes will be very sparse, we optimise
* vector to store an extent map after the database is loaded. // vector to store an extent map after the database is loaded.
*/
typedef enum { typedef enum {
TYPE_KEY, TYPE_KEY,
@ -125,32 +119,15 @@ struct trie_node_key {
struct trie_node_arr { struct trie_node_arr {
trie_nodetype type; trie_nodetype type;
unsigned char min, max; /* INCLUSIVE endpoints of the extent range */ unsigned char min, max; // INCLUSIVE endpoints of the extent range
struct trie_node *arr[]; /* dynamic size at allocation time */ 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 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) static struct trie_node *new_node_key(TermKeyType type, TermKeySym sym, int modmask, int modset)
{ {
struct trie_node_key *n = malloc(sizeof(*n)); struct trie_node_key *n = xmalloc(sizeof(*n));
if(!n)
return NULL;
n->type = TYPE_KEY; n->type = TYPE_KEY;
@ -164,16 +141,15 @@ static struct trie_node *new_node_key(TermKeyType type, TermKeySym sym, int modm
static struct trie_node *new_node_arr(unsigned char min, unsigned char max) 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])); struct trie_node_arr *n = xmalloc(sizeof(*n) + (max - min + 1) * sizeof(n->arr[0]));
if(!n)
return NULL;
n->type = TYPE_ARR; n->type = TYPE_ARR;
n->min = min; n->max = max; n->min = min; n->max = max;
int i; int i;
for(i = min; i <= max; i++) for (i = min; i <= max; i++) {
n->arr[i - min] = NULL; n->arr[i - min] = NULL;
}
return (struct trie_node *)n; return (struct trie_node *)n;
} }
@ -184,11 +160,11 @@ static struct trie_node *lookup_next(struct trie_node *n, unsigned char b)
case TYPE_KEY: case TYPE_KEY:
fprintf(stderr, "ABORT: lookup_next within a TYPE_KEY node\n"); fprintf(stderr, "ABORT: lookup_next within a TYPE_KEY node\n");
abort(); abort();
case TYPE_ARR: case TYPE_ARR: {
{
struct trie_node_arr *nar = (struct trie_node_arr *)n; struct trie_node_arr *nar = (struct trie_node_arr *)n;
if(b < nar->min || b > nar->max) if (b < nar->min || b > nar->max) {
return NULL; return NULL;
}
return nar->arr[b - nar->min]; return nar->arr[b - nar->min];
} }
} }
@ -201,48 +177,50 @@ static void free_trie(struct trie_node *n)
switch (n->type) { switch (n->type) {
case TYPE_KEY: case TYPE_KEY:
break; break;
case TYPE_ARR: case TYPE_ARR: {
{
struct trie_node_arr *nar = (struct trie_node_arr *)n; struct trie_node_arr *nar = (struct trie_node_arr *)n;
int i; int i;
for(i = nar->min; i <= nar->max; i++) for (i = nar->min; i <= nar->max; i++) {
if(nar->arr[i - nar->min]) if (nar->arr[i - nar->min]) {
free_trie(nar->arr[i - nar->min]); free_trie(nar->arr[i - nar->min]);
}
}
break; break;
} }
} }
free(n); xfree(n);
} }
static struct trie_node *compress_trie(struct trie_node *n) static struct trie_node *compress_trie(struct trie_node *n)
{ {
if(!n) if (!n) {
return NULL; return NULL;
}
switch (n->type) { switch (n->type) {
case TYPE_KEY: case TYPE_KEY:
return n; return n;
case TYPE_ARR: case TYPE_ARR: {
{
struct trie_node_arr *nar = (struct trie_node_arr *)n; struct trie_node_arr *nar = (struct trie_node_arr *)n;
unsigned char min, max; unsigned char min, max;
// Find the real bounds // Find the real bounds
for(min = 0; !nar->arr[min]; min++) for (min = 0; !nar->arr[min]; min++) {
if (min == 255 && !nar->arr[min]) { if (min == 255 && !nar->arr[min]) {
free(nar); xfree(nar);
return new_node_arr(1, 0); return new_node_arr(1, 0);
} }
}
for(max = 0xff; !nar->arr[max]; max--) for (max = 0xff; !nar->arr[max]; max--) {}
;
struct trie_node_arr *new = (struct trie_node_arr *)new_node_arr(min, max); struct trie_node_arr *new = (struct trie_node_arr *)new_node_arr(min, max);
int i; int i;
for(i = min; i <= max; i++) for (i = min; i <= max; i++) {
new->arr[i - min] = compress_trie(nar->arr[i]); new->arr[i - min] = compress_trie(nar->arr[i]);
}
free(nar); xfree(nar);
return (struct trie_node *)new; 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; const char *value = NULL;
#ifdef HAVE_UNIBILIUM if (ti->unibi) {
if(ti->unibi)
value = unibi_get_str_by_name(ti->unibi, name); 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); 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; 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); insert_seq(ti, value, node);
return true; return true;
@ -278,39 +255,29 @@ static int load_terminfo(TermKeyTI *ti)
{ {
int i; int i;
#ifdef HAVE_UNIBILIUM
unibi_term *unibi = ti->unibi; 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); ti->root = new_node_arr(0, 0xff);
if(!ti->root) if (!ti->root) {
return 0; return 0;
}
/* First the regular key strings // First the regular key strings
*/
for (i = 0; funcs[i].funcname; i++) { for (i = 0; funcs[i].funcname; i++) {
char name[MAX_FUNCNAME + 5 + 1]; char name[MAX_FUNCNAME + 5 + 1];
sprintf(name, "key_%s", funcs[i].funcname); sprintf(name, "key_%s", funcs[i].funcname); // NOLINT(runtime/printf)
if (!try_load_terminfo_key(ti, name, &(struct keyinfo){ if (!try_load_terminfo_key(ti, name, &(struct keyinfo){
.type = funcs[i].type, .type = funcs[i].type,
.sym = funcs[i].sym, .sym = funcs[i].sym,
.modifier_mask = funcs[i].mods, .modifier_mask = funcs[i].mods,
.modifier_set = funcs[i].mods, .modifier_set = funcs[i].mods,
})) })) {
continue; continue;
}
/* Maybe it has a shifted version */ // Maybe it has a shifted version
sprintf(name, "key_s%s", funcs[i].funcname); sprintf(name, "key_s%s", funcs[i].funcname); // NOLINT(runtime/printf)
try_load_terminfo_key(ti, name, &(struct keyinfo){ try_load_terminfo_key(ti, name, &(struct keyinfo){
.type = funcs[i].type, .type = funcs[i].type,
.sym = funcs[i].sym, .sym = funcs[i].sym,
@ -319,244 +286,223 @@ static int load_terminfo(TermKeyTI *ti)
}); });
} }
/* Now the F<digit> keys // Now the F<digit> keys
*/
for (i = 1; i < 255; i++) { for (i = 1; i < 255; i++) {
char name[9]; char name[9];
sprintf(name, "key_f%d", i); sprintf(name, "key_f%d", i); // NOLINT(runtime/printf)
if (!try_load_terminfo_key(ti, name, &(struct keyinfo){ if (!try_load_terminfo_key(ti, name, &(struct keyinfo){
.type = TERMKEY_TYPE_FUNCTION, .type = TERMKEY_TYPE_FUNCTION,
.sym = i, .sym = i,
.modifier_mask = 0, .modifier_mask = 0,
.modifier_set = 0, .modifier_set = 0,
})) })) {
break; break;
} }
}
/* Finally mouse mode */ // Finally mouse mode
{ {
const char *value = NULL; const char *value = NULL;
#ifdef HAVE_UNIBILIUM if (ti->unibi) {
if(ti->unibi)
value = unibi_get_str_by_name(ti->unibi, "key_mouse"); 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); 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 // 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" // give X10 encoding. We'll only accept this if it's exactly "\e[M"
*/
if (value && streq(value, "\x1b[M")) { if (value && streq(value, "\x1b[M")) {
struct trie_node *node = new_node_key(TERMKEY_TYPE_MOUSE, 0, 0, 0); struct trie_node *node = new_node_key(TERMKEY_TYPE_MOUSE, 0, 0, 0);
insert_seq(ti, value, node); insert_seq(ti, value, node);
} }
} }
/* Take copies of these terminfo strings, in case we build multiple termkey // Take copies of these terminfo strings, in case we build multiple termkey
* instances for multiple different termtypes, and it's different by the // instances for multiple different termtypes, and it's different by the
* time we want to use it // time we want to use it
*/ const char *keypad_xmit = unibi
#ifdef HAVE_UNIBILIUM ? unibi_get_str(unibi, unibi_keypad_xmit)
const char *keypad_xmit = unibi ? : NULL;
unibi_get_str(unibi, unibi_keypad_xmit) :
NULL;
#endif
if(keypad_xmit) if (keypad_xmit) {
ti->start_string = strdup(keypad_xmit); ti->start_string = xstrdup(keypad_xmit);
else } else {
ti->start_string = NULL; ti->start_string = NULL;
}
#ifdef HAVE_UNIBILIUM const char *keypad_local = unibi
const char *keypad_local = unibi ? ? unibi_get_str(unibi, unibi_keypad_local)
unibi_get_str(unibi, unibi_keypad_local) : : NULL;
NULL;
#endif
if(keypad_local) if (keypad_local) {
ti->stop_string = strdup(keypad_local); ti->stop_string = xstrdup(keypad_local);
else } else {
ti->stop_string = NULL; ti->stop_string = NULL;
}
#ifdef HAVE_UNIBILIUM if (unibi) {
if(unibi)
unibi_destroy(unibi); unibi_destroy(unibi);
}
ti->unibi = NULL; ti->unibi = NULL;
#else
if(ti->term)
free(ti->term);
ti->term = NULL;
#endif
ti->root = compress_trie(ti->root); ti->root = compress_trie(ti->root);
return 1; 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); TermKeyTI *ti = xmalloc(sizeof *ti);
if(!ti)
return NULL;
ti->tk = tk; ti->tk = tk;
ti->root = NULL; ti->root = NULL;
ti->start_string = NULL; ti->start_string = NULL;
ti->stop_string = NULL; ti->stop_string = NULL;
#ifdef HAVE_UNIBILIUM
ti->unibi = unibi_from_term(term); ti->unibi = unibi_from_term(term);
int saved_errno = errno; int saved_errno = errno;
if (!ti->unibi && saved_errno != ENOENT) { if (!ti->unibi && saved_errno != ENOENT) {
free(ti); xfree(ti);
return NULL; return NULL;
} }
/* ti->unibi may be NULL if errno == ENOENT. That means the terminal wasn't // 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 // known. Lets keep going because if we get getstr hook that might invent
* new strings for us // 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
return ti; return ti;
} }
static int start_driver(TermKey *tk, void *info) int start_driver_ti(TermKey *tk, void *info)
{ {
TermKeyTI *ti = info; TermKeyTI *ti = info;
struct stat statbuf; struct stat statbuf;
char *start_string; char *start_string;
size_t len; size_t len;
if(!ti->root) if (!ti->root) {
load_terminfo(ti); load_terminfo(ti);
}
start_string = ti->start_string; start_string = ti->start_string;
if(tk->fd == -1 || !start_string) if (tk->fd == -1 || !start_string) {
return 1; return 1;
}
/* The terminfo database will contain keys in application cursor key mode. // The terminfo database will contain keys in application cursor key mode.
* We may need to enable that mode // We may need to enable that mode
*/
/* There's no point trying to write() to a pipe */ // There's no point trying to write() to a pipe
if(fstat(tk->fd, &statbuf) == -1) if (fstat(tk->fd, &statbuf) == -1) {
return 0; return 0;
}
#ifndef _WIN32 #ifndef _WIN32
if(S_ISFIFO(statbuf.st_mode)) if (S_ISFIFO(statbuf.st_mode)) {
return 1; return 1;
}
#endif #endif
// Can't call putp or tputs because they suck and don't give us fd control // Can't call putp or tputs because they suck and don't give us fd control
len = strlen(start_string); len = strlen(start_string);
while (len) { while (len) {
size_t written = write(tk->fd, start_string, len); size_t written = (size_t)write(tk->fd, start_string, (unsigned)len);
if(written == -1) if (written == (size_t)-1) {
return 0; return 0;
}
start_string += written; start_string += written;
len -= written; len -= written;
} }
return 1; return 1;
} }
static int stop_driver(TermKey *tk, void *info) int stop_driver_ti(TermKey *tk, void *info)
{ {
TermKeyTI *ti = info; TermKeyTI *ti = info;
struct stat statbuf; struct stat statbuf;
char *stop_string = ti->stop_string; char *stop_string = ti->stop_string;
size_t len; size_t len;
if(tk->fd == -1 || !stop_string) if (tk->fd == -1 || !stop_string) {
return 1; return 1;
}
/* There's no point trying to write() to a pipe */ // There's no point trying to write() to a pipe
if(fstat(tk->fd, &statbuf) == -1) if (fstat(tk->fd, &statbuf) == -1) {
return 0; return 0;
}
#ifndef _WIN32 #ifndef _WIN32
if(S_ISFIFO(statbuf.st_mode)) if (S_ISFIFO(statbuf.st_mode)) {
return 1; return 1;
}
#endif #endif
/* The terminfo database will contain keys in application cursor key mode. // The terminfo database will contain keys in application cursor key mode.
* We may need to enable that mode // We may need to enable that mode
*/
// Can't call putp or tputs because they suck and don't give us fd control // Can't call putp or tputs because they suck and don't give us fd control
len = strlen(stop_string); len = strlen(stop_string);
while (len) { while (len) {
size_t written = write(tk->fd, stop_string, len); size_t written = (size_t)write(tk->fd, stop_string, (unsigned)len);
if(written == -1) if (written == (size_t)-1) {
return 0; return 0;
}
stop_string += written; stop_string += written;
len -= written; len -= written;
} }
return 1; return 1;
} }
static void free_driver(void *info) void free_driver_ti(void *info)
{ {
TermKeyTI *ti = info; TermKeyTI *ti = info;
free_trie(ti->root); free_trie(ti->root);
if(ti->start_string) if (ti->start_string) {
free(ti->start_string); xfree(ti->start_string);
}
if(ti->stop_string) if (ti->stop_string) {
free(ti->stop_string); xfree(ti->stop_string);
}
#ifdef HAVE_UNIBILIUM if (ti->unibi) {
if(ti->unibi)
unibi_destroy(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)]) #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; TermKeyTI *ti = info;
if(tk->buffcount == 0) if (tk->buffcount == 0) {
return tk->is_closed ? TERMKEY_RES_EOF : TERMKEY_RES_NONE; return tk->is_closed ? TERMKEY_RES_EOF : TERMKEY_RES_NONE;
}
struct trie_node *p = ti->root; struct trie_node *p = ti->root;
unsigned int pos = 0; unsigned pos = 0;
while (pos < tk->buffcount) { while (pos < tk->buffcount) {
p = lookup_next(p, CHARAT(pos)); p = lookup_next(p, CHARAT(pos));
if(!p) if (!p) {
break; break;
}
pos++; pos++;
if(p->type != TYPE_KEY) if (p->type != TYPE_KEY) {
continue; continue;
}
struct trie_node_key *nk = (struct trie_node_key *)p; struct trie_node_key *nk = (struct trie_node_key *)p;
if (nk->key.type == TERMKEY_TYPE_MOUSE) { if (nk->key.type == TERMKEY_TYPE_MOUSE) {
@ -568,8 +514,9 @@ static TermKeyResult peekkey(TermKey *tk, void *info, TermKeyKey *key, int force
tk->buffstart -= pos; tk->buffstart -= pos;
tk->buffcount += pos; tk->buffcount += pos;
if(mouse_result == TERMKEY_RES_KEY) if (mouse_result == TERMKEY_RES_KEY) {
*nbytep += pos; *nbytep += pos;
}
return mouse_result; 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 // If p is not NULL then we hadn't walked off the end yet, so we have a
// partial match // partial match
if(p && !force) if (p && !force) {
return TERMKEY_RES_AGAIN; return TERMKEY_RES_AGAIN;
}
return TERMKEY_RES_NONE; 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 because we'll be using it as an array subscript
unsigned char b; unsigned char b;
while((b = seq[pos])) { while ((b = (unsigned char)seq[pos])) {
struct trie_node *next = lookup_next(p, b); struct trie_node *next = lookup_next(p, b);
if(!next) if (!next) {
break; break;
}
p = next; p = next;
pos++; pos++;
} }
while((b = seq[pos])) { while ((b = (unsigned char)seq[pos])) {
struct trie_node *next; struct trie_node *next;
if(seq[pos+1]) if (seq[pos + 1]) {
// Intermediate node // Intermediate node
next = new_node_arr(0, 0xff); next = new_node_arr(0, 0xff);
else } else {
// Final key node // Final key node
next = node; next = node;
}
if(!next) if (!next) {
return 0; return 0;
}
switch (p->type) { switch (p->type) {
case TYPE_ARR: case TYPE_ARR: {
{
struct trie_node_arr *nar = (struct trie_node_arr *)p; struct trie_node_arr *nar = (struct trie_node_arr *)p;
if (b < nar->min || b > nar->max) { 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", fprintf(stderr,
"ASSERT FAIL: Trie insert at 0x%02x is outside of extent bounds (0x%02x..0x%02x)\n",
b, nar->min, nar->max); b, nar->min, nar->max);
abort(); abort();
} }
@ -640,15 +591,3 @@ static int insert_seq(TermKeyTI *ti, const char *seq, struct trie_node *node)
return 1; 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,15 +1,14 @@
#ifndef GUARD_TERMKEY_INTERNAL_H_ #pragma once
#define GUARD_TERMKEY_INTERNAL_H_
#include <stdint.h>
#include "nvim/tui/termkey/termkey_defs.h"
#define HAVE_TERMIOS #define HAVE_TERMIOS
#ifdef _WIN32 #ifdef _WIN32
# undef HAVE_TERMIOS # undef HAVE_TERMIOS
#endif #endif
#include "termkey.h"
#include <stdint.h>
#ifdef HAVE_TERMIOS #ifdef HAVE_TERMIOS
# include <termios.h> # include <termios.h>
#endif #endif
@ -19,8 +18,7 @@
typedef SSIZE_T ssize_t; typedef SSIZE_T ssize_t;
#endif #endif
struct TermKeyDriver struct TermKeyDriver {
{
const char *name; const char *name;
void *(*new_driver)(TermKey *tk, const char *term); void *(*new_driver)(TermKey *tk, const char *term);
void (*free_driver)(void *info); void (*free_driver)(void *info);
@ -51,8 +49,8 @@ struct TermKey {
size_t buffstart; // First offset in buffer size_t buffstart; // First offset in buffer
size_t buffcount; // NUMBER of entires valid in buffer size_t buffcount; // NUMBER of entires valid in buffer
size_t buffsize; // Total malloc'ed size size_t buffsize; // Total malloc'ed size
size_t hightide; /* Position beyond buffstart at which peekkey() should next start size_t hightide; // Position beyond buffstart at which peekkey() should next start
* normally 0, but see also termkey_interpret_csi */ // normally 0, but see also termkey_interpret_csi
#ifdef HAVE_TERMIOS #ifdef HAVE_TERMIOS
struct termios restore_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 // Now some "protected" methods for the driver to call but which we don't
// want exported as real symbols in the library // want exported as real symbols in the library
struct { 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_simple)(TermKey *tk, TermKeyKey *key, int force, size_t *nbytes);
TermKeyResult (*peekkey_mouse)(TermKey *tk, TermKeyKey *key, size_t *nbytes); TermKeyResult (*peekkey_mouse)(TermKey *tk, TermKeyKey *key, size_t *nbytes);
} method; } method;
@ -86,27 +84,26 @@ struct TermKey {
static inline void termkey_key_get_linecol(const TermKeyKey *key, int *line, int *col) 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; *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; *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) static inline void termkey_key_set_linecol(TermKeyKey *key, int line, int col)
{ {
if(line > 0xfff) if (line > 0xfff) {
line = 0xfff; line = 0xfff;
if(col > 0x7ff)
col = 0x7ff;
key->code.mouse[1] = (line & 0x0ff);
key->code.mouse[2] = (col & 0x0ff);
key->code.mouse[3] = (line & 0xf00) >> 8 | (col & 0x300) >> 4;
} }
extern struct TermKeyDriver termkey_driver_csi; if (col > 0x7ff) {
extern struct TermKeyDriver termkey_driver_ti; col = 0x7ff;
}
#endif key->code.mouse[1] = (char)(line & 0x0ff);
key->code.mouse[2] = (char)(col & 0x0ff);
key->code.mouse[3] = (line & 0xf00) >> 8 | (col & 0x300) >> 4;
}

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 "vterm_internal.h"
#include <stdio.h> #include <stdio.h>
#include "utf8.h" #include "nvim/tui/termkey/termkey.h"
void vterm_keyboard_unichar(VTerm *vt, uint32_t c, VTermModifier mod) void vterm_keyboard_unichar(VTerm *vt, uint32_t c, VTermModifier mod)
{ {

View File

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