mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
Merge PR #1820 'Reimplement builtin terminal UI with termkey/unibilium'
This commit is contained in:
commit
0429857689
@ -182,6 +182,14 @@ include_directories(SYSTEM ${MSGPACK_INCLUDE_DIRS})
|
||||
find_package(LuaJit REQUIRED)
|
||||
include_directories(SYSTEM ${LUAJIT_INCLUDE_DIRS})
|
||||
|
||||
set(LIBUNIBILIUM_USE_STATIC ON)
|
||||
find_package(LibUnibilium REQUIRED)
|
||||
include_directories(SYSTEM ${LIBUNIBILIUM_INCLUDE_DIRS})
|
||||
|
||||
set(LIBTERMKEY_USE_STATIC ON)
|
||||
find_package(LibTermkey REQUIRED)
|
||||
include_directories(SYSTEM ${LIBTERMEY_INCLUDE_DIRS})
|
||||
|
||||
find_package(LibIntl)
|
||||
if(LibIntl_FOUND)
|
||||
include_directories(SYSTEM ${LibIntl_INCLUDE_DIRS})
|
||||
|
@ -23,7 +23,6 @@ check_include_files(locale.h HAVE_LOCALE_H)
|
||||
check_include_files(pwd.h HAVE_PWD_H)
|
||||
check_include_files(strings.h HAVE_STRINGS_H)
|
||||
check_include_files(stropts.h HAVE_STROPTS_H)
|
||||
check_include_files(sys/ioctl.h HAVE_SYS_IOCTL_H)
|
||||
check_include_files(sys/param.h HAVE_SYS_PARAM_H)
|
||||
check_include_files(sys/time.h HAVE_SYS_TIME_H)
|
||||
check_include_files(sys/wait.h HAVE_SYS_WAIT_H)
|
||||
@ -33,9 +32,6 @@ if(NOT HAVE_SYS_WAIT_H AND UNIX)
|
||||
endif()
|
||||
check_include_files(sys/utsname.h HAVE_SYS_UTSNAME_H)
|
||||
check_include_files(utime.h HAVE_UTIME_H)
|
||||
check_include_files(termcap.h HAVE_TERMCAP_H)
|
||||
check_include_files(termios.h HAVE_TERMIOS_H)
|
||||
check_include_files(termio.h HAVE_TERMIO_H)
|
||||
check_include_files(unistd.h HAVE_UNISTD_H)
|
||||
check_include_files(utime.h HAVE_UTIME_H)
|
||||
|
||||
|
@ -53,15 +53,10 @@
|
||||
#cmakedefine HAVE_STRINGS_H
|
||||
#cmakedefine HAVE_STRNCASECMP
|
||||
#cmakedefine HAVE_STROPTS_H
|
||||
#cmakedefine HAVE_SYS_IOCTL_H
|
||||
#cmakedefine HAVE_SYS_PARAM_H
|
||||
#cmakedefine HAVE_SYS_TIME_H
|
||||
#cmakedefine HAVE_SYS_UTSNAME_H
|
||||
#cmakedefine HAVE_SYS_WAIT_H
|
||||
#cmakedefine HAVE_TERMCAP_H
|
||||
#cmakedefine HAVE_TERMIOS_H
|
||||
#cmakedefine HAVE_TERMIO_H
|
||||
#define HAVE_TGETENT 1
|
||||
#cmakedefine HAVE_UNISTD_H
|
||||
#define HAVE_UP_BC_PC 1
|
||||
#cmakedefine HAVE_UTIME
|
||||
@ -70,8 +65,6 @@
|
||||
#cmakedefine HAVE_WORKING_LIBINTL
|
||||
#define RETSIGTYPE void
|
||||
#define SIGRETURN return
|
||||
#define TERMINFO 1
|
||||
#define TGETENT_ZERO_ERR 0
|
||||
#define TIME_WITH_SYS_TIME 1
|
||||
#cmakedefine UNIX
|
||||
#define USEMAN_S 1
|
||||
@ -79,9 +72,3 @@
|
||||
#define FEAT_BROWSE
|
||||
#define FEAT_CSCOPE
|
||||
#define FEAT_MOUSE
|
||||
#define FEAT_MOUSE_NET
|
||||
#define FEAT_MOUSE_SGR
|
||||
#define FEAT_MOUSE_TTY
|
||||
#define FEAT_MOUSE_URXVT
|
||||
#define FEAT_MOUSE_XTERM
|
||||
#define FEAT_TERMRESPONSE
|
||||
|
@ -287,7 +287,7 @@ MsgpackRpcRequestHandler msgpack_rpc_get_handler_for(const char *name,
|
||||
{
|
||||
String m = {
|
||||
.data=(char *)name,
|
||||
.size=min(name_len, ]]..max_fname_len..[[)
|
||||
.size=MIN(name_len, ]]..max_fname_len..[[)
|
||||
};
|
||||
MsgpackRpcRequestHandler rv =
|
||||
map_get(String, MsgpackRpcRequestHandler)(methods, m);
|
||||
|
@ -26,13 +26,16 @@ file(MAKE_DIRECTORY ${GENERATED_DIR}/os)
|
||||
file(MAKE_DIRECTORY ${GENERATED_DIR}/api)
|
||||
file(MAKE_DIRECTORY ${GENERATED_DIR}/api/private)
|
||||
file(MAKE_DIRECTORY ${GENERATED_DIR}/msgpack_rpc)
|
||||
file(MAKE_DIRECTORY ${GENERATED_DIR}/tui)
|
||||
file(MAKE_DIRECTORY ${GENERATED_INCLUDES_DIR})
|
||||
file(MAKE_DIRECTORY ${GENERATED_INCLUDES_DIR}/os)
|
||||
file(MAKE_DIRECTORY ${GENERATED_INCLUDES_DIR}/api)
|
||||
file(MAKE_DIRECTORY ${GENERATED_INCLUDES_DIR}/api/private)
|
||||
file(MAKE_DIRECTORY ${GENERATED_INCLUDES_DIR}/msgpack_rpc)
|
||||
file(MAKE_DIRECTORY ${GENERATED_INCLUDES_DIR}/tui)
|
||||
|
||||
file(GLOB NEOVIM_SOURCES *.c os/*.c api/*.c api/private/*.c msgpack_rpc/*.c)
|
||||
file(GLOB NEOVIM_SOURCES *.c os/*.c api/*.c api/private/*.c msgpack_rpc/*.c
|
||||
tui/*.c)
|
||||
file(GLOB_RECURSE NEOVIM_HEADERS *.h)
|
||||
|
||||
foreach(sfile ${NEOVIM_SOURCES})
|
||||
@ -164,19 +167,6 @@ if (LibIntl_FOUND)
|
||||
list(APPEND NVIM_LINK_LIBRARIES ${LibIntl_LIBRARY})
|
||||
endif()
|
||||
|
||||
check_library_exists(curses tgetent "" HAVE_LIBCURSES)
|
||||
if (HAVE_LIBCURSES)
|
||||
list(APPEND NVIM_LINK_LIBRARIES curses)
|
||||
else()
|
||||
check_library_exists(tinfo tgetent "" HAVE_LIBTINFO)
|
||||
if (HAVE_LIBTINFO)
|
||||
list(APPEND NVIM_LINK_LIBRARIES tinfo)
|
||||
else()
|
||||
find_package(Curses REQUIRED)
|
||||
list(APPEND NVIM_LINK_LIBRARIES ${CURSES_LIBRARY})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(Iconv_LIBRARIES)
|
||||
list(APPEND NVIM_LINK_LIBRARIES ${Iconv_LIBRARIES})
|
||||
endif()
|
||||
@ -186,8 +176,12 @@ list(APPEND NVIM_LINK_LIBRARIES
|
||||
${LIBUV_LIBRARIES}
|
||||
${MSGPACK_LIBRARIES}
|
||||
${LUAJIT_LIBRARIES}
|
||||
${LIBTICKIT_LIBRARIES}
|
||||
${LIBTERMKEY_LIBRARIES}
|
||||
${LIBUNIBILIUM_LIBRARIES}
|
||||
m
|
||||
${CMAKE_THREAD_LIBS_INIT})
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
)
|
||||
|
||||
add_executable(nvim ${NEOVIM_GENERATED_SOURCES} ${NEOVIM_SOURCES}
|
||||
${NEOVIM_HEADERS})
|
||||
|
@ -1849,25 +1849,6 @@ int hex2nr(int c)
|
||||
return c - '0';
|
||||
}
|
||||
|
||||
#if defined(FEAT_TERMRESPONSE) || defined(FEAT_GUI_GTK)
|
||||
|
||||
/// Convert two hex characters to a byte.
|
||||
/// Return -1 if one of the characters is not hex.
|
||||
///
|
||||
/// @param p
|
||||
///
|
||||
/// @return The two hex characters converted to a byte or -1 if one of the
|
||||
/// character is not hex.
|
||||
int hexhex2nr(char_u *p)
|
||||
{
|
||||
if (!vim_isxdigit(p[0]) || !vim_isxdigit(p[1])) {
|
||||
return -1;
|
||||
}
|
||||
return (hex2nr(p[0]) << 4) + hex2nr(p[1]);
|
||||
}
|
||||
|
||||
#endif // if defined(FEAT_TERMRESPONSE) || defined(FEAT_GUI_GTK)
|
||||
|
||||
/// Return true if "str" starts with a backslash that should be removed.
|
||||
/// For WIN32 this is only done when the character after the
|
||||
/// backslash is not a normal file name character.
|
||||
|
@ -9955,14 +9955,8 @@ static void f_has(typval_T *argvars, typval_T *rettv)
|
||||
#endif
|
||||
"tag_binary",
|
||||
"tag_old_static",
|
||||
#ifdef TERMINFO
|
||||
"terminfo",
|
||||
#endif
|
||||
"termresponse",
|
||||
"textobjects",
|
||||
#ifdef HAVE_TGETENT
|
||||
"tgetent",
|
||||
#endif
|
||||
"title",
|
||||
"user-commands", /* was accidentally included in 5.4 */
|
||||
"user_commands",
|
||||
@ -14424,13 +14418,10 @@ static void f_synIDattr(typval_T *argvars, typval_T *rettv)
|
||||
if (argvars[2].v_type != VAR_UNKNOWN) {
|
||||
mode = get_tv_string_buf(&argvars[2], modebuf);
|
||||
modec = TOLOWER_ASC(mode[0]);
|
||||
if (modec != 't' && modec != 'c' && modec != 'g')
|
||||
if (modec != 'c' && modec != 'g')
|
||||
modec = 0; /* replace invalid with current */
|
||||
} else {
|
||||
if (abstract_ui || t_colors > 1)
|
||||
modec = 'c';
|
||||
else
|
||||
modec = 't';
|
||||
modec = 'c';
|
||||
}
|
||||
|
||||
|
||||
@ -18080,21 +18071,6 @@ static int function_exists(char_u *name)
|
||||
return n;
|
||||
}
|
||||
|
||||
char_u *get_expanded_name(char_u *name, int check)
|
||||
{
|
||||
char_u *nm = name;
|
||||
char_u *p;
|
||||
|
||||
p = trans_function_name(&nm, FALSE, TFN_INT|TFN_QUIET, NULL);
|
||||
|
||||
if (p != NULL && *nm == NUL)
|
||||
if (!check || translated_function_exists(p))
|
||||
return p;
|
||||
|
||||
free(p);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/// Return TRUE if "name" looks like a builtin function name: starts with a
|
||||
/// lower case letter and doesn't contain AUTOLOAD_CHAR.
|
||||
/// "len" is the length of "name", or -1 for NUL terminated.
|
||||
|
@ -1232,9 +1232,6 @@ do_shell (
|
||||
* avoid having to type return below.
|
||||
*/
|
||||
msg_putchar('\r'); /* put cursor at start of line */
|
||||
if (!autocmd_busy) {
|
||||
stoptermcap();
|
||||
}
|
||||
msg_putchar('\n'); /* may shift screen one line up */
|
||||
|
||||
/* warning message before calling the shell */
|
||||
@ -1292,8 +1289,6 @@ do_shell (
|
||||
wait_return(msg_silent == 0);
|
||||
no_wait_return = save_nwr;
|
||||
}
|
||||
|
||||
starttermcap(); /* start termcap if not done by wait_return() */
|
||||
}
|
||||
|
||||
/* display any error messages now */
|
||||
|
@ -2483,7 +2483,7 @@ return {
|
||||
{
|
||||
command='winpos',
|
||||
flags=bit.bor(EXTRA, TRLBAR, CMDWIN),
|
||||
func='ex_winpos',
|
||||
func='ex_ni',
|
||||
},
|
||||
{
|
||||
command='wnext',
|
||||
|
@ -155,10 +155,6 @@ void do_debug(char_u *cmd)
|
||||
#define CMD_INTERRUPT 6
|
||||
|
||||
|
||||
/* Make sure we are in raw mode and start termcap mode. Might have side
|
||||
* effects... */
|
||||
starttermcap();
|
||||
|
||||
++RedrawingDisabled; /* don't redisplay the window */
|
||||
++no_wait_return; /* don't wait for return */
|
||||
did_emsg = FALSE; /* don't use error from debugged stuff */
|
||||
|
@ -146,10 +146,6 @@ struct dbg_stuff {
|
||||
# define gui_mch_find_dialog ex_ni
|
||||
# define gui_mch_replace_dialog ex_ni
|
||||
# define ex_helpfind ex_ni
|
||||
#if defined(FEAT_GUI) || defined(UNIX) || defined(MSWIN)
|
||||
#else
|
||||
# define ex_winpos ex_ni
|
||||
#endif
|
||||
static int did_lcd; /* whether ":lcd" was produced for a session */
|
||||
#ifndef HAVE_WORKING_LIBINTL
|
||||
# define ex_language ex_ni
|
||||
@ -5397,13 +5393,11 @@ static void ex_stop(exarg_T *eap)
|
||||
windgoto((int)Rows - 1, 0);
|
||||
out_char('\n');
|
||||
out_flush();
|
||||
stoptermcap();
|
||||
out_flush(); /* needed for SUN to restore xterm buffer */
|
||||
mch_restore_title(3); /* restore window titles */
|
||||
ui_suspend(); /* call machine specific function */
|
||||
maketitle();
|
||||
resettitle(); /* force updating the title */
|
||||
starttermcap();
|
||||
scroll_start(); /* scroll screen before redrawing */
|
||||
redraw_later_clear();
|
||||
shell_resized(); /* may have resized window */
|
||||
@ -6438,7 +6432,7 @@ static void ex_winsize(exarg_T *eap)
|
||||
p = arg;
|
||||
h = getdigits_int(&arg);
|
||||
if (*p != NUL && *arg == NUL)
|
||||
screen_resize(w, h, TRUE);
|
||||
screen_resize(w, h);
|
||||
else
|
||||
EMSG(_("E465: :winsize requires two number arguments"));
|
||||
}
|
||||
@ -6473,35 +6467,6 @@ static void ex_wincmd(exarg_T *eap)
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(FEAT_GUI) || defined(UNIX) || defined(MSWIN)
|
||||
/*
|
||||
* ":winpos".
|
||||
*/
|
||||
static void ex_winpos(exarg_T *eap)
|
||||
{
|
||||
int x, y;
|
||||
char_u *arg = eap->arg;
|
||||
char_u *p;
|
||||
|
||||
if (*arg == NUL) {
|
||||
EMSG(_("E188: Obtaining window position not implemented for this platform"));
|
||||
} else {
|
||||
x = getdigits_int(&arg);
|
||||
arg = skipwhite(arg);
|
||||
p = arg;
|
||||
y = getdigits_int(&arg);
|
||||
if (*p == NUL || *arg != NUL) {
|
||||
EMSG(_("E466: :winpos requires two number arguments"));
|
||||
return;
|
||||
}
|
||||
# ifdef HAVE_TGETENT
|
||||
if (*T_CWP)
|
||||
term_set_winpos(x, y);
|
||||
# endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Handle command that work like operators: ":delete", ":yank", ":>" and ":<".
|
||||
*/
|
||||
|
@ -4618,35 +4618,6 @@ int del_history_idx(int histype, int idx)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Very specific function to remove the value in ":set key=val" from the
|
||||
* history.
|
||||
*/
|
||||
void remove_key_from_history(void)
|
||||
{
|
||||
char_u *p;
|
||||
int i;
|
||||
|
||||
i = hisidx[HIST_CMD];
|
||||
if (i < 0)
|
||||
return;
|
||||
p = history[HIST_CMD][i].hisstr;
|
||||
if (p != NULL)
|
||||
for (; *p; ++p)
|
||||
if (STRNCMP(p, "key", 3) == 0 && !isalpha(p[3])) {
|
||||
p = vim_strchr(p + 3, '=');
|
||||
if (p == NULL)
|
||||
break;
|
||||
++p;
|
||||
for (i = 0; p[i] && !vim_iswhite(p[i]); ++i)
|
||||
if (p[i] == '\\' && p[i + 1])
|
||||
++i;
|
||||
STRMOVE(p, p + i);
|
||||
--p;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Get indices "num1,num2" that specify a range within a list (not a range of
|
||||
* text lines in a buffer!) from a string. Used for ":history" and ":clist".
|
||||
|
@ -1813,7 +1813,6 @@ failed:
|
||||
* Switch on raw mode now and clear the screen.
|
||||
*/
|
||||
if (read_stdin) {
|
||||
starttermcap();
|
||||
screenclear();
|
||||
}
|
||||
|
||||
@ -6471,12 +6470,6 @@ int has_cmdundefined(void)
|
||||
return first_autopat[(int)EVENT_CMDUNDEFINED] != NULL;
|
||||
}
|
||||
|
||||
/// @returns true when there is an FuncUndefined autocommand defined.
|
||||
int has_funcundefined(void)
|
||||
{
|
||||
return first_autopat[(int)EVENT_FUNCUNDEFINED] != NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
apply_autocmds_group (
|
||||
event_T event,
|
||||
|
@ -198,23 +198,3 @@ void ga_append(garray_T *gap, char c)
|
||||
{
|
||||
GA_APPEND(char, gap, c);
|
||||
}
|
||||
|
||||
#if defined(UNIX) || defined(WIN3264)
|
||||
|
||||
/// Append the text in "gap" below the cursor line and clear "gap".
|
||||
///
|
||||
/// @param gap
|
||||
void append_ga_line(garray_T *gap)
|
||||
{
|
||||
// Remove trailing CR.
|
||||
if (!GA_EMPTY(gap)
|
||||
&& !curbuf->b_p_bin
|
||||
&& (((char_u *)gap->ga_data)[gap->ga_len - 1] == CAR)) {
|
||||
gap->ga_len--;
|
||||
}
|
||||
ga_append(gap, NUL);
|
||||
ml_append(curwin->w_cursor.lnum++, gap->ga_data, 0, FALSE);
|
||||
gap->ga_len = 0;
|
||||
}
|
||||
|
||||
#endif // if defined(UNIX) || defined(WIN3264)
|
||||
|
@ -1203,7 +1203,6 @@ void save_typeahead(tasave_T *tp)
|
||||
readbuf1.bh_first.b_next = NULL;
|
||||
tp->save_readbuf2 = readbuf2;
|
||||
readbuf2.bh_first.b_next = NULL;
|
||||
tp->save_inputbuf = input_buffer_save();
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1224,7 +1223,6 @@ void restore_typeahead(tasave_T *tp)
|
||||
readbuf1 = tp->save_readbuf1;
|
||||
free_buff(&readbuf2);
|
||||
readbuf2 = tp->save_readbuf2;
|
||||
input_buffer_restore(tp->save_inputbuf);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1545,22 +1543,6 @@ int vpeekc(void)
|
||||
return vgetorpeek(FALSE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Like vpeekc(), but don't allow mapping. Do allow checking for terminal
|
||||
* codes.
|
||||
*/
|
||||
int vpeekc_nomap(void)
|
||||
{
|
||||
int c;
|
||||
|
||||
++no_mapping;
|
||||
++allow_keys;
|
||||
c = vpeekc();
|
||||
--no_mapping;
|
||||
--allow_keys;
|
||||
return c;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if any character is available, also half an escape sequence.
|
||||
* Trick: when no typeahead found, but there is something in the typeahead
|
||||
@ -1929,8 +1911,6 @@ static int vgetorpeek(int advance)
|
||||
|
||||
if ((mp == NULL || max_mlen >= mp_match_len)
|
||||
&& keylen != KEYLEN_PART_MAP) {
|
||||
int save_keylen = keylen;
|
||||
|
||||
/*
|
||||
* When no matching mapping found or found a
|
||||
* non-matching mapping that matches at least what the
|
||||
@ -1947,25 +1927,7 @@ static int vgetorpeek(int advance)
|
||||
|| (p_remap && typebuf.tb_noremap[
|
||||
typebuf.tb_off] == RM_YES))
|
||||
&& !timedout) {
|
||||
keylen = check_termcode(max_mlen + 1,
|
||||
NULL, 0, NULL);
|
||||
|
||||
/* If no termcode matched but 'pastetoggle'
|
||||
* matched partially it's like an incomplete key
|
||||
* sequence. */
|
||||
if (keylen == 0 && save_keylen == KEYLEN_PART_KEY)
|
||||
keylen = KEYLEN_PART_KEY;
|
||||
|
||||
/*
|
||||
* When getting a partial match, but the last
|
||||
* characters were not typed, don't wait for a
|
||||
* typed character to complete the termcode.
|
||||
* This helps a lot when a ":normal" command ends
|
||||
* in an ESC.
|
||||
*/
|
||||
if (keylen < 0
|
||||
&& typebuf.tb_len == typebuf.tb_maplen)
|
||||
keylen = 0;
|
||||
keylen = 0;
|
||||
} else
|
||||
keylen = 0;
|
||||
if (keylen == 0) { /* no matching terminal code */
|
||||
@ -2515,29 +2477,27 @@ fix_input_buffer (
|
||||
int script /* TRUE when reading from a script */
|
||||
)
|
||||
{
|
||||
if (abstract_ui) {
|
||||
// Should not escape K_SPECIAL/CSI while in embedded mode because vim key
|
||||
// codes keys are processed in input.c/input_enqueue.
|
||||
if (!using_script()) {
|
||||
// Should not escape K_SPECIAL/CSI reading input from the user because vim
|
||||
// key codes keys are processed in input.c/input_enqueue.
|
||||
buf[len] = NUL;
|
||||
return len;
|
||||
}
|
||||
|
||||
// Reading from script, need to process special bytes
|
||||
int i;
|
||||
char_u *p = buf;
|
||||
|
||||
/*
|
||||
* Two characters are special: NUL and K_SPECIAL.
|
||||
* When compiled With the GUI CSI is also special.
|
||||
* Replace NUL by K_SPECIAL KS_ZERO KE_FILLER
|
||||
* Replace K_SPECIAL by K_SPECIAL KS_SPECIAL KE_FILLER
|
||||
* Replace CSI by K_SPECIAL KS_EXTRA KE_CSI
|
||||
* Don't replace K_SPECIAL when reading a script file.
|
||||
*/
|
||||
// Two characters are special: NUL and K_SPECIAL.
|
||||
// Replace NUL by K_SPECIAL KS_ZERO KE_FILLER
|
||||
// Replace K_SPECIAL by K_SPECIAL KS_SPECIAL KE_FILLER
|
||||
// Replace CSI by K_SPECIAL KS_EXTRA KE_CSI
|
||||
// Don't replace K_SPECIAL when reading a script file.
|
||||
for (i = len; --i >= 0; ++p) {
|
||||
if (p[0] == NUL
|
||||
|| (p[0] == K_SPECIAL
|
||||
&& !script
|
||||
&& (i < 2 || p[1] != KS_EXTRA || is_user_input(p[2])))) {
|
||||
&& (i < 2 || p[1] != KS_EXTRA))) {
|
||||
memmove(p + 3, p + 1, (size_t)i);
|
||||
p[2] = K_THIRD(p[0]);
|
||||
p[1] = K_SECOND(p[0]);
|
||||
@ -2546,7 +2506,7 @@ fix_input_buffer (
|
||||
len += 2;
|
||||
}
|
||||
}
|
||||
*p = NUL; /* add trailing NUL */
|
||||
*p = NUL; // add trailing NUL
|
||||
return len;
|
||||
}
|
||||
|
||||
@ -3772,11 +3732,6 @@ eval_map_expr (
|
||||
return res;
|
||||
}
|
||||
|
||||
static bool is_user_input(int k)
|
||||
{
|
||||
return k != (int)KE_EVENT && k != (int)KE_CURSORHOLD;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy "p" to allocated memory, escaping K_SPECIAL and CSI so that the result
|
||||
* can be put in the typeahead buffer.
|
||||
|
@ -904,13 +904,10 @@ EXTERN char_u *use_viminfo INIT(= NULL); /* name of viminfo file to use */
|
||||
EXTERN FILE *scriptin[NSCRIPT]; /* streams to read script from */
|
||||
EXTERN int curscript INIT(= 0); /* index in scriptin[] */
|
||||
EXTERN FILE *scriptout INIT(= NULL); /* stream to write script to */
|
||||
EXTERN int read_cmd_fd INIT(= 0); /* fd to read commands from */
|
||||
|
||||
/* volatile because it is used in signal handler catch_sigint(). */
|
||||
EXTERN volatile int got_int INIT(= FALSE); /* set to TRUE when interrupt
|
||||
signal occurred */
|
||||
EXTERN int termcap_active INIT(= FALSE); /* set by starttermcap() */
|
||||
EXTERN int cur_tmode INIT(= TMODE_COOK); /* input terminal mode */
|
||||
EXTERN int bangredo INIT(= FALSE); /* set to TRUE with ! command */
|
||||
EXTERN int searchcmdlen; /* length of previous search cmd */
|
||||
EXTERN int reg_do_extmatch INIT(= 0); /* Used when compiling regexp:
|
||||
@ -1237,14 +1234,8 @@ EXTERN FILE *time_fd INIT(= NULL); /* where to write startup timing */
|
||||
EXTERN int ignored;
|
||||
EXTERN char *ignoredp;
|
||||
|
||||
/* Temporarily moved these static variables to assist in migrating from
|
||||
* os_unix.c */
|
||||
EXTERN int curr_tmode INIT(= TMODE_COOK); /* contains current terminal mode */
|
||||
|
||||
// If a msgpack-rpc channel should be started over stdin/stdout
|
||||
EXTERN bool embedded_mode INIT(= false);
|
||||
// Using the "abstract_ui" termcap
|
||||
EXTERN bool abstract_ui INIT(= false);
|
||||
|
||||
/// Used to track the status of external functions.
|
||||
/// Currently only used for iconv().
|
||||
|
@ -617,10 +617,7 @@ void ex_hardcopy(exarg_T *eap)
|
||||
eap->forceit) == FAIL)
|
||||
return;
|
||||
|
||||
if (t_colors > 1)
|
||||
settings.modec = 'c';
|
||||
else
|
||||
settings.modec = 't';
|
||||
settings.modec = 'c';
|
||||
|
||||
if (!syntax_present(curwin))
|
||||
settings.do_syntax = FALSE;
|
||||
|
@ -752,26 +752,3 @@ int get_mouse_button(int code, bool *is_click, bool *is_drag)
|
||||
}
|
||||
return 0; /* Shouldn't get here */
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the appropriate pseudo mouse event token (KE_LEFTMOUSE etc) based on
|
||||
* the given information about which mouse button is down, and whether the
|
||||
* mouse was clicked, dragged or released.
|
||||
*/
|
||||
int
|
||||
get_pseudo_mouse_code (
|
||||
int button, /* eg MOUSE_LEFT */
|
||||
int is_click,
|
||||
int is_drag
|
||||
)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; mouse_table[i].pseudo_code; i++)
|
||||
if (button == mouse_table[i].button
|
||||
&& is_click == mouse_table[i].is_click
|
||||
&& is_drag == mouse_table[i].is_drag) {
|
||||
return mouse_table[i].pseudo_code;
|
||||
}
|
||||
return (int)KE_IGNORE; /* not recognized, ignore it */
|
||||
}
|
||||
|
139
src/nvim/main.c
139
src/nvim/main.c
@ -95,7 +95,12 @@ typedef struct {
|
||||
char_u *use_ef; /* 'errorfile' from -q argument */
|
||||
|
||||
int want_full_screen;
|
||||
bool stdout_isatty; /* is stdout a terminal? */
|
||||
bool input_isatty; // stdin is a terminal
|
||||
bool output_isatty; // stdout is a terminal
|
||||
bool err_isatty; // stderr is a terminal
|
||||
bool headless; // Dont try to start an user interface
|
||||
// or read/write to stdio(unless
|
||||
// embedding)
|
||||
char_u *term; /* specified terminal name */
|
||||
int no_swap_file; /* "-n" argument used */
|
||||
int use_debug_break_level;
|
||||
@ -197,9 +202,7 @@ int main(int argc, char **argv)
|
||||
|
||||
early_init();
|
||||
|
||||
/*
|
||||
* Check if we have an interactive window.
|
||||
*/
|
||||
// Check if we have an interactive window.
|
||||
check_and_set_isatty(¶ms);
|
||||
|
||||
/*
|
||||
@ -242,34 +245,20 @@ int main(int argc, char **argv)
|
||||
printf(_("%d files to edit\n"), GARGCOUNT);
|
||||
|
||||
if (params.want_full_screen && !silent_mode) {
|
||||
if (embedded_mode) {
|
||||
// embedded mode implies abstract_ui
|
||||
termcapinit((uint8_t *)"abstract_ui");
|
||||
} else {
|
||||
// set terminal name and get terminal capabilities (will set full_screen)
|
||||
// Do some initialization of the screen
|
||||
termcapinit(params.term);
|
||||
}
|
||||
termcapinit((uint8_t *)"abstract_ui");
|
||||
screen_start(); /* don't know where cursor is now */
|
||||
TIME_MSG("Termcap init");
|
||||
}
|
||||
|
||||
event_init();
|
||||
|
||||
if (abstract_ui) {
|
||||
full_screen = true;
|
||||
t_colors = 256;
|
||||
T_CCO = (uint8_t *)"256";
|
||||
} else {
|
||||
// Print a warning if stdout is not a terminal TODO(tarruda): Remove this
|
||||
// check once the new terminal UI is implemented
|
||||
check_tty(¶ms);
|
||||
}
|
||||
full_screen = true;
|
||||
t_colors = 256;
|
||||
T_CCO = (uint8_t *)"256";
|
||||
check_tty(¶ms);
|
||||
|
||||
/*
|
||||
* Set the default values for the options that use Rows and Columns.
|
||||
*/
|
||||
ui_get_shellsize(); /* inits Rows and Columns */
|
||||
win_init_size();
|
||||
/* Set the 'diff' option now, so that it can be checked for in a .vimrc
|
||||
* file. There is no buffer yet though. */
|
||||
@ -382,25 +371,22 @@ int main(int argc, char **argv)
|
||||
newline_on_exit = TRUE;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* When done something that is not allowed or error message call
|
||||
* wait_return. This must be done before starttermcap(), because it may
|
||||
* switch to another screen. It must be done after settmode(TMODE_RAW),
|
||||
* because we want to react on a single key stroke.
|
||||
* Call settmode and starttermcap here, so the T_KS and T_TI may be
|
||||
* defined by termcapinit and redefined in .exrc.
|
||||
*/
|
||||
settmode(TMODE_RAW);
|
||||
TIME_MSG("setting raw mode");
|
||||
if (!params.headless && (params.output_isatty || params.err_isatty)) {
|
||||
if (params.input_isatty && (need_wait_return || msg_didany)) {
|
||||
// Since at this point there's no UI instance running yet, error messages
|
||||
// would have been printed to stdout. Before starting (which can result
|
||||
// in a alternate screen buffer being shown) we need confirmation that
|
||||
// the user has seen the messages and that is done with a call to
|
||||
// wait_return. For that to work, stdin must be openend temporarily.
|
||||
input_start_stdin();
|
||||
wait_return(TRUE);
|
||||
TIME_MSG("waiting for return");
|
||||
input_stop_stdin();
|
||||
}
|
||||
|
||||
if (need_wait_return || msg_didany) {
|
||||
wait_return(TRUE);
|
||||
TIME_MSG("waiting for return");
|
||||
ui_builtin_start();
|
||||
}
|
||||
|
||||
starttermcap(); // start termcap if not done by wait_return()
|
||||
TIME_MSG("start termcap");
|
||||
may_req_ambiguous_char_width();
|
||||
setmouse(); // may start using the mouse
|
||||
|
||||
if (scroll_region) {
|
||||
@ -480,10 +466,6 @@ int main(int argc, char **argv)
|
||||
no_wait_return = FALSE;
|
||||
starting = 0;
|
||||
|
||||
/* Requesting the termresponse is postponed until here, so that a "-c q"
|
||||
* argument doesn't make it appear in the shell Vim was started from. */
|
||||
may_req_termresponse();
|
||||
|
||||
/* start in insert mode */
|
||||
if (p_im)
|
||||
need_start_insertmode = TRUE;
|
||||
@ -965,14 +947,14 @@ static void command_line_scan(mparm_T *parmp)
|
||||
c = argv[0][argv_idx++];
|
||||
switch (c) {
|
||||
case NUL: /* "vim -" read from stdin */
|
||||
/* "ex -" silent mode */
|
||||
if (exmode_active)
|
||||
if (exmode_active) {
|
||||
// "ex -" silent mode
|
||||
silent_mode = TRUE;
|
||||
else {
|
||||
if (parmp->edit_type != EDIT_NONE)
|
||||
} else {
|
||||
if (parmp->edit_type != EDIT_NONE) {
|
||||
mainerr(ME_TOO_MANY_ARGS, argv[0]);
|
||||
}
|
||||
parmp->edit_type = EDIT_STDIN;
|
||||
read_cmd_fd = 2; /* read from stderr instead of stdin */
|
||||
}
|
||||
argv_idx = -1; /* skip to next argument */
|
||||
break;
|
||||
@ -1004,8 +986,11 @@ static void command_line_scan(mparm_T *parmp)
|
||||
}
|
||||
|
||||
mch_exit(0);
|
||||
} else if (STRICMP(argv[0] + argv_idx, "headless") == 0) {
|
||||
parmp->headless = true;
|
||||
} else if (STRICMP(argv[0] + argv_idx, "embed") == 0) {
|
||||
embedded_mode = true;
|
||||
parmp->headless = true;
|
||||
} else if (STRNICMP(argv[0] + argv_idx, "literal", 7) == 0) {
|
||||
#if !defined(UNIX)
|
||||
parmp->literal = TRUE;
|
||||
@ -1418,7 +1403,8 @@ static void init_params(mparm_T *paramp, int argc, char **argv)
|
||||
memset(paramp, 0, sizeof(*paramp));
|
||||
paramp->argc = argc;
|
||||
paramp->argv = argv;
|
||||
paramp->want_full_screen = TRUE;
|
||||
paramp->headless = false;
|
||||
paramp->want_full_screen = true;
|
||||
paramp->use_debug_break_level = -1;
|
||||
paramp->window_count = -1;
|
||||
}
|
||||
@ -1439,15 +1425,13 @@ static void init_startuptime(mparm_T *paramp)
|
||||
starttime = time(NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if we have an interactive window.
|
||||
*/
|
||||
static void check_and_set_isatty(mparm_T *paramp)
|
||||
{
|
||||
paramp->stdout_isatty = os_isatty(STDOUT_FILENO);
|
||||
paramp->input_isatty = os_isatty(fileno(stdin));
|
||||
paramp->output_isatty = os_isatty(fileno(stdout));
|
||||
paramp->err_isatty = os_isatty(fileno(stderr));
|
||||
TIME_MSG("window checked");
|
||||
}
|
||||
|
||||
/*
|
||||
* Get filename from command line, given that there is one.
|
||||
*/
|
||||
@ -1532,28 +1516,43 @@ static void handle_tag(char_u *tagname)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Print a warning if stdout is not a terminal.
|
||||
* When starting in Ex mode and commands come from a file, set Silent mode.
|
||||
*/
|
||||
// Print a warning if stdout is not a terminal.
|
||||
// When starting in Ex mode and commands come from a file, set Silent mode.
|
||||
static void check_tty(mparm_T *parmp)
|
||||
{
|
||||
if (parmp->headless) {
|
||||
return;
|
||||
}
|
||||
|
||||
// is active input a terminal?
|
||||
bool input_isatty = os_isatty(read_cmd_fd);
|
||||
if (exmode_active) {
|
||||
if (!input_isatty)
|
||||
silent_mode = TRUE;
|
||||
} else if (parmp->want_full_screen && (!parmp->stdout_isatty || !input_isatty)
|
||||
) {
|
||||
if (!parmp->stdout_isatty)
|
||||
if (!parmp->input_isatty) {
|
||||
silent_mode = true;
|
||||
}
|
||||
} else if (parmp->want_full_screen && (!parmp->err_isatty
|
||||
&& (!parmp->output_isatty || !parmp->input_isatty))) {
|
||||
|
||||
if (!parmp->output_isatty) {
|
||||
mch_errmsg(_("Vim: Warning: Output is not to a terminal\n"));
|
||||
if (!input_isatty)
|
||||
}
|
||||
|
||||
if (!parmp->input_isatty) {
|
||||
mch_errmsg(_("Vim: Warning: Input is not from a terminal\n"));
|
||||
}
|
||||
|
||||
out_flush();
|
||||
if (scriptin[0] == NULL)
|
||||
|
||||
if (scriptin[0] == NULL) {
|
||||
os_delay(2000L, true);
|
||||
}
|
||||
|
||||
TIME_MSG("Warning delay");
|
||||
}
|
||||
|
||||
if (parmp->edit_type != EDIT_STDIN && !parmp->input_isatty) {
|
||||
// read commands from directly from stdin
|
||||
input_start_stdin();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1573,13 +1572,6 @@ static void read_stdin(void)
|
||||
msg_didany = i;
|
||||
TIME_MSG("reading stdin");
|
||||
check_swap_exists_action();
|
||||
/*
|
||||
* Close stdin and dup it from stderr. Required for GPM to work
|
||||
* properly, and for running external commands.
|
||||
* Is there any other system that cannot do this?
|
||||
*/
|
||||
close(0);
|
||||
ignored = dup(2);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2104,6 +2096,7 @@ static void usage(void)
|
||||
mch_msg(_(" -i <nviminfo> Use <nviminfo> instead of .nviminfo\n"));
|
||||
mch_msg(_(" --api-info Dump API metadata serialized to msgpack and exit\n"));
|
||||
mch_msg(_(" --embed Use stdin/stdout as a msgpack-rpc channel\n"));
|
||||
mch_msg(_(" --headless Don't start a user interface\n"));
|
||||
mch_msg(_(" --version Print version information and exit\n"));
|
||||
mch_msg(_(" -h | --help Print this help message and exit\n"));
|
||||
|
||||
|
@ -100,7 +100,7 @@ static inline khint_t String_hash(String s)
|
||||
|
||||
static inline bool String_eq(String a, String b)
|
||||
{
|
||||
return strncmp(a.data, b.data, min(a.size, b.size)) == 0;
|
||||
return strncmp(a.data, b.data, MIN(a.size, b.size)) == 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -40,6 +40,7 @@
|
||||
#include "nvim/screen.h"
|
||||
#include "nvim/strings.h"
|
||||
#include "nvim/term.h"
|
||||
#include "nvim/ui.h"
|
||||
#include "nvim/mouse.h"
|
||||
#include "nvim/os/os.h"
|
||||
#include "nvim/os/input.h"
|
||||
@ -915,15 +916,6 @@ void wait_return(int redraw)
|
||||
State = oldState; /* restore State before set_shellsize */
|
||||
setmouse();
|
||||
msg_check();
|
||||
|
||||
#if defined(UNIX)
|
||||
/*
|
||||
* When switching screens, we need to output an extra newline on exit.
|
||||
*/
|
||||
if (swapping_screen() && !termcap_active)
|
||||
newline_on_exit = TRUE;
|
||||
#endif
|
||||
|
||||
need_wait_return = FALSE;
|
||||
did_wait_return = TRUE;
|
||||
emsg_on_display = FALSE; /* can delete error message now */
|
||||
@ -936,11 +928,9 @@ void wait_return(int redraw)
|
||||
}
|
||||
|
||||
if (tmpState == SETWSIZE) { /* got resize event while in vgetc() */
|
||||
starttermcap(); /* start termcap before redrawing */
|
||||
shell_resized();
|
||||
} else if (!skip_redraw
|
||||
&& (redraw == TRUE || (msg_scrolled != 0 && redraw != -1))) {
|
||||
starttermcap(); /* start termcap before redrawing */
|
||||
redraw_later(VALID);
|
||||
}
|
||||
}
|
||||
@ -978,17 +968,6 @@ void set_keep_msg(char_u *s, int attr)
|
||||
keep_msg_attr = attr;
|
||||
}
|
||||
|
||||
/*
|
||||
* If there currently is a message being displayed, set "keep_msg" to it, so
|
||||
* that it will be displayed again after redraw.
|
||||
*/
|
||||
void set_keep_msg_from_hist(void)
|
||||
{
|
||||
if (keep_msg == NULL && last_msg_hist != NULL && msg_scrolled == 0
|
||||
&& (State & NORMAL))
|
||||
set_keep_msg(last_msg_hist->msg, last_msg_hist->attr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Prepare for outputting characters in the command line.
|
||||
*/
|
||||
@ -1780,19 +1759,6 @@ static void msg_scroll_up(void)
|
||||
{
|
||||
/* scrolling up always works */
|
||||
screen_del_lines(0, 0, 1, (int)Rows, TRUE, NULL);
|
||||
|
||||
if (!can_clear((char_u *)" ")) {
|
||||
/* Scrolling up doesn't result in the right background. Set the
|
||||
* background here. It's not efficient, but avoids that we have to do
|
||||
* it all over the code. */
|
||||
screen_fill((int)Rows - 1, (int)Rows, 0, (int)Columns, ' ', ' ', 0);
|
||||
|
||||
/* Also clear the last char of the last but one line if it was not
|
||||
* cleared before to avoid a scroll-up. */
|
||||
if (ScreenAttrs[LineOffset[Rows - 2] + Columns - 1] == (sattr_T)-1)
|
||||
screen_fill((int)Rows - 2, (int)Rows - 1,
|
||||
(int)Columns - 1, (int)Columns, ' ', ' ', 0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1975,19 +1941,11 @@ static void t_puts(int *t_col, char_u *t_s, char_u *s, int attr)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns TRUE when messages should be printed with mch_errmsg().
|
||||
* This is used when there is no valid screen, so we can see error messages.
|
||||
* If termcap is not active, we may be writing in an alternate console
|
||||
* window, cursor positioning may not work correctly (window size may be
|
||||
* different, e.g. for Win32 console) or we just don't know where the
|
||||
* cursor is.
|
||||
*/
|
||||
// Returns TRUE when messages should be printed to stdout/stderr, which
|
||||
// happens when no UIs are attached and nvim is not being embedded
|
||||
int msg_use_printf(void)
|
||||
{
|
||||
return !msg_check_screen()
|
||||
|| (swapping_screen() && !termcap_active)
|
||||
;
|
||||
return !embedded_mode && !ui_active();
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2378,24 +2336,6 @@ void repeat_message(void)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* msg_check_screen - check if the screen is initialized.
|
||||
* Also check msg_row and msg_col, if they are too big it may cause a crash.
|
||||
* While starting the GUI the terminal codes will be set for the GUI, but the
|
||||
* output goes to the terminal. Don't use the terminal codes then.
|
||||
*/
|
||||
static int msg_check_screen(void)
|
||||
{
|
||||
if (!full_screen || !screen_valid(FALSE))
|
||||
return FALSE;
|
||||
|
||||
if (msg_row >= Rows)
|
||||
msg_row = Rows - 1;
|
||||
if (msg_col >= Columns)
|
||||
msg_col = Columns - 1;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Clear from current message position to end of screen.
|
||||
* Skip this when ":silent" was used, no need to clear for redirection.
|
||||
|
@ -2395,11 +2395,6 @@ int get_keystroke(void)
|
||||
} else if (len > 0)
|
||||
++waited; /* keep track of the waiting time */
|
||||
|
||||
/* Incomplete termcode and not timed out yet: get more characters */
|
||||
if ((n = check_termcode(1, buf, buflen, &len)) < 0
|
||||
&& (!p_ttimeout || waited * 100L < (p_ttm < 0 ? p_tm : p_ttm)))
|
||||
continue;
|
||||
|
||||
if (n == KEYLEN_REMOVED) { /* key code removed */
|
||||
if (must_redraw != 0 && !need_wait_return && (State & CMDLINE) == 0) {
|
||||
/* Redrawing was postponed, do it now. */
|
||||
@ -3301,28 +3296,6 @@ home_replace_save (
|
||||
return dst;
|
||||
}
|
||||
|
||||
void prepare_to_exit(void)
|
||||
{
|
||||
#if defined(SIGHUP) && defined(SIG_IGN)
|
||||
/* Ignore SIGHUP, because a dropped connection causes a read error, which
|
||||
* makes Vim exit and then handling SIGHUP causes various reentrance
|
||||
* problems. */
|
||||
signal(SIGHUP, SIG_IGN);
|
||||
#endif
|
||||
|
||||
{
|
||||
windgoto((int)Rows - 1, 0);
|
||||
|
||||
/*
|
||||
* Switch terminal mode back now, so messages end up on the "normal"
|
||||
* screen (if there are two screens).
|
||||
*/
|
||||
settmode(TMODE_COOK);
|
||||
stoptermcap();
|
||||
out_flush();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Preserve files and exit.
|
||||
* When called IObuff must contain a message.
|
||||
@ -3340,9 +3313,6 @@ void preserve_exit(void)
|
||||
}
|
||||
|
||||
really_exiting = true;
|
||||
|
||||
prepare_to_exit();
|
||||
|
||||
out_str(IObuff);
|
||||
screen_start(); // don't know where cursor is now
|
||||
out_flush();
|
||||
|
@ -451,12 +451,6 @@ void setmouse(void)
|
||||
if (*p_mouse == NUL)
|
||||
return;
|
||||
|
||||
/* don't switch mouse on when not in raw mode (Ex mode) */
|
||||
if (!abstract_ui && cur_tmode != TMODE_RAW) {
|
||||
mch_setmouse(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (VIsual_active)
|
||||
checkfor = MOUSE_VISUAL;
|
||||
else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE)
|
||||
|
@ -103,9 +103,7 @@ void channel_init(void)
|
||||
channel_from_stdio();
|
||||
}
|
||||
|
||||
if (abstract_ui) {
|
||||
remote_ui_init();
|
||||
}
|
||||
remote_ui_init();
|
||||
}
|
||||
|
||||
/// Teardown the module
|
||||
@ -176,13 +174,6 @@ void channel_from_stream(uv_stream_t *stream)
|
||||
channel->data.streams.uv = stream;
|
||||
}
|
||||
|
||||
bool channel_exists(uint64_t id)
|
||||
{
|
||||
Channel *channel;
|
||||
return (channel = pmap_get(uint64_t)(channels, id)) != NULL
|
||||
&& !channel->closed;
|
||||
}
|
||||
|
||||
/// Sends event/arguments to channel
|
||||
///
|
||||
/// @param id The channel id. If 0, the event will be sent to all
|
||||
@ -665,10 +656,7 @@ static void on_stdio_close(Event e)
|
||||
|
||||
static void free_channel(Channel *channel)
|
||||
{
|
||||
if (abstract_ui) {
|
||||
remote_ui_disconnect(channel->id);
|
||||
}
|
||||
|
||||
remote_ui_disconnect(channel->id);
|
||||
pmap_del(uint64_t)(channels, channel->id);
|
||||
msgpack_unpacker_free(channel->unpacker);
|
||||
|
||||
|
@ -295,22 +295,6 @@ void msgpack_rpc_from_dictionary(Dictionary result, msgpack_packer *res)
|
||||
}
|
||||
}
|
||||
|
||||
/// Finishes the msgpack-rpc call with an error message.
|
||||
///
|
||||
/// @param msg The error message
|
||||
/// @param res A packer that contains the response
|
||||
void msgpack_rpc_error(char *msg, msgpack_packer *res)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
size_t len = strlen(msg);
|
||||
|
||||
// error message
|
||||
msgpack_pack_bin(res, len);
|
||||
msgpack_pack_bin_body(res, msg, len);
|
||||
// Nil result
|
||||
msgpack_pack_nil(res);
|
||||
}
|
||||
|
||||
/// Handler executed when an invalid method name is passed
|
||||
Object msgpack_rpc_handle_missing_method(uint64_t channel_id,
|
||||
uint64_t request_id,
|
||||
|
@ -1834,7 +1834,6 @@ do_mouse (
|
||||
bool fixindent /* PUT_FIXINDENT if fixing indent necessary */
|
||||
)
|
||||
{
|
||||
static bool do_always = false; /* ignore 'mouse' setting next time */
|
||||
static bool got_click = false; /* got a click some time back */
|
||||
|
||||
int which_button; /* MOUSE_LEFT, _MIDDLE or _RIGHT */
|
||||
@ -1859,23 +1858,6 @@ do_mouse (
|
||||
|
||||
save_cursor = curwin->w_cursor;
|
||||
|
||||
// When "abstract_ui" is active, always recognize mouse events, otherwise:
|
||||
// - Ignore mouse event in normal mode if 'mouse' doesn't include 'n'.
|
||||
// - Ignore mouse event in visual mode if 'mouse' doesn't include 'v'.
|
||||
// - For command line and insert mode 'mouse' is checked before calling
|
||||
// do_mouse().
|
||||
if (!abstract_ui) {
|
||||
if (do_always)
|
||||
do_always = false;
|
||||
else {
|
||||
if (VIsual_active) {
|
||||
if (!mouse_has(MOUSE_VISUAL))
|
||||
return false;
|
||||
} else if (State == NORMAL && !mouse_has(MOUSE_NORMAL))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (;; ) {
|
||||
which_button = get_mouse_button(KEY2TERMCAP1(c), &is_click, &is_drag);
|
||||
if (is_drag) {
|
||||
@ -1996,7 +1978,6 @@ do_mouse (
|
||||
stuffcharReadbuff('y');
|
||||
stuffcharReadbuff(K_MIDDLEMOUSE);
|
||||
}
|
||||
do_always = true; /* ignore 'mouse' setting next time */
|
||||
return false;
|
||||
}
|
||||
/*
|
||||
|
@ -4226,23 +4226,6 @@ did_set_string_option (
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if defined(FEAT_MOUSE_TTY) && defined(UNIX)
|
||||
/* 'ttymouse' */
|
||||
else if (varp == &p_ttym) {
|
||||
/* Switch the mouse off before changing the escape sequences used for
|
||||
* that. */
|
||||
mch_setmouse(FALSE);
|
||||
if (opt_strings_flags(p_ttym, p_ttym_values, &ttym_flags, FALSE) != OK)
|
||||
errmsg = e_invarg;
|
||||
else
|
||||
check_mouse_termcode();
|
||||
if (termcap_active)
|
||||
setmouse(); /* may switch it on again */
|
||||
}
|
||||
#endif
|
||||
|
||||
/* 'selection' */
|
||||
else if (varp == &p_sel) {
|
||||
if (*p_sel == NUL
|
||||
@ -5439,8 +5422,7 @@ set_num_option (
|
||||
curbuf->b_p_iminsert = B_IMODE_NONE;
|
||||
}
|
||||
p_iminsert = curbuf->b_p_iminsert;
|
||||
if (termcap_active) /* don't do this in the alternate screen */
|
||||
showmode();
|
||||
showmode();
|
||||
/* Show/unshow value of 'keymap' in status lines. */
|
||||
status_redraw_curbuf();
|
||||
} else if (pp == &p_window) {
|
||||
@ -5559,12 +5541,11 @@ set_num_option (
|
||||
*/
|
||||
if (old_Rows != Rows || old_Columns != Columns) {
|
||||
/* Changing the screen size is not allowed while updating the screen. */
|
||||
if (updating_screen)
|
||||
if (updating_screen) {
|
||||
*pp = old_value;
|
||||
else if (full_screen
|
||||
)
|
||||
screen_resize((int)Columns, (int)Rows, TRUE);
|
||||
else {
|
||||
} else if (full_screen) {
|
||||
screen_resize((int)Columns, (int)Rows);
|
||||
} else {
|
||||
/* Postpone the resizing; check the size and cmdline position for
|
||||
* messages. */
|
||||
check_shellsize();
|
||||
@ -5970,27 +5951,6 @@ set_option_value (
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the terminal code for a terminal option.
|
||||
* Returns NULL when not found.
|
||||
*/
|
||||
char_u *get_term_code(char_u *tname)
|
||||
{
|
||||
int opt_idx;
|
||||
char_u *varp;
|
||||
|
||||
if (tname[0] != 't' || tname[1] != '_' ||
|
||||
tname[2] == NUL || tname[3] == NUL)
|
||||
return NULL;
|
||||
if ((opt_idx = findoption(tname)) >= 0) {
|
||||
varp = get_varp(&(options[opt_idx]));
|
||||
if (varp != NULL)
|
||||
varp = *(char_u **)(varp);
|
||||
return varp;
|
||||
}
|
||||
return find_termcode(tname + 2);
|
||||
}
|
||||
|
||||
char_u *get_highlight_default(void)
|
||||
{
|
||||
int i;
|
||||
@ -6414,7 +6374,6 @@ void clear_termoptions(void)
|
||||
*/
|
||||
mch_setmouse(FALSE); /* switch mouse off */
|
||||
mch_restore_title(3); /* restore window titles */
|
||||
stoptermcap(); /* stop termcap mode */
|
||||
|
||||
free_termoptions();
|
||||
}
|
||||
@ -7831,17 +7790,6 @@ int option_was_set(char_u *name)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset the flag indicating option "name" was set.
|
||||
*/
|
||||
void reset_option_was_set(char_u *name)
|
||||
{
|
||||
int idx = findoption(name);
|
||||
|
||||
if (idx >= 0)
|
||||
options[idx].flags &= ~P_WAS_SET;
|
||||
}
|
||||
|
||||
/*
|
||||
* fill_breakat_flags() -- called when 'breakat' changes value.
|
||||
*/
|
||||
|
@ -54,7 +54,6 @@ void event_init(void)
|
||||
wstream_init();
|
||||
// Initialize input events
|
||||
input_init();
|
||||
input_start();
|
||||
// Timer to wake the event loop if a timeout argument is passed to
|
||||
// `event_poll`
|
||||
// Signals
|
||||
@ -75,13 +74,11 @@ void event_teardown(void)
|
||||
|
||||
process_events_from(immediate_events);
|
||||
process_events_from(deferred_events);
|
||||
|
||||
input_stop_stdin();
|
||||
channel_teardown();
|
||||
job_teardown();
|
||||
server_teardown();
|
||||
signal_teardown();
|
||||
input_stop();
|
||||
input_teardown();
|
||||
// this last `uv_run` will return after all handles are stopped, it will
|
||||
// also take care of finishing any uv_close calls made by other *_teardown
|
||||
// functions.
|
||||
|
@ -19,7 +19,6 @@
|
||||
#include "nvim/fileio.h"
|
||||
#include "nvim/ex_cmds2.h"
|
||||
#include "nvim/getchar.h"
|
||||
#include "nvim/term.h"
|
||||
#include "nvim/main.h"
|
||||
#include "nvim/misc1.h"
|
||||
|
||||
@ -32,9 +31,9 @@ typedef enum {
|
||||
kInputEof
|
||||
} InbufPollResult;
|
||||
|
||||
static RStream *read_stream;
|
||||
static RBuffer *read_buffer, *input_buffer;
|
||||
static bool eof = false, started_reading = false;
|
||||
static RStream *read_stream = NULL;
|
||||
static RBuffer *read_buffer = NULL, *input_buffer = NULL;
|
||||
static bool eof = false;
|
||||
|
||||
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
||||
# include "os/input.c.generated.h"
|
||||
@ -45,43 +44,29 @@ static bool eof = false, started_reading = false;
|
||||
void input_init(void)
|
||||
{
|
||||
input_buffer = rbuffer_new(INPUT_BUFFER_SIZE + MAX_KEY_CODE_LEN);
|
||||
}
|
||||
|
||||
if (abstract_ui) {
|
||||
void input_start_stdin(void)
|
||||
{
|
||||
if (read_stream) {
|
||||
return;
|
||||
}
|
||||
|
||||
read_buffer = rbuffer_new(READ_BUFFER_SIZE);
|
||||
read_stream = rstream_new(read_cb, read_buffer, NULL);
|
||||
rstream_set_file(read_stream, read_cmd_fd);
|
||||
}
|
||||
|
||||
void input_teardown(void)
|
||||
{
|
||||
if (abstract_ui) {
|
||||
return;
|
||||
}
|
||||
|
||||
rstream_free(read_stream);
|
||||
}
|
||||
|
||||
// Listen for input
|
||||
void input_start(void)
|
||||
{
|
||||
if (abstract_ui) {
|
||||
return;
|
||||
}
|
||||
|
||||
rstream_set_file(read_stream, fileno(stdin));
|
||||
rstream_start(read_stream);
|
||||
}
|
||||
|
||||
// Stop listening for input
|
||||
void input_stop(void)
|
||||
void input_stop_stdin(void)
|
||||
{
|
||||
if (abstract_ui) {
|
||||
if (!read_stream) {
|
||||
return;
|
||||
}
|
||||
|
||||
rstream_stop(read_stream);
|
||||
rstream_free(read_stream);
|
||||
read_stream = NULL;
|
||||
}
|
||||
|
||||
// Low level input function.
|
||||
@ -141,11 +126,9 @@ bool os_char_avail(void)
|
||||
}
|
||||
|
||||
// Check for CTRL-C typed by reading all available characters.
|
||||
// In cooked mode we should get SIGINT, no need to check.
|
||||
void os_breakcheck(void)
|
||||
{
|
||||
if (curr_tmode == TMODE_RAW)
|
||||
input_poll(0);
|
||||
event_poll(0);
|
||||
}
|
||||
|
||||
/// Test whether a file descriptor refers to a terminal.
|
||||
@ -157,34 +140,13 @@ bool os_isatty(int fd)
|
||||
return uv_guess_handle(fd) == UV_TTY;
|
||||
}
|
||||
|
||||
/// Return the contents of the input buffer and make it empty. The returned
|
||||
/// pointer must be passed to `input_buffer_restore()` later.
|
||||
String input_buffer_save(void)
|
||||
{
|
||||
size_t inbuf_size = rbuffer_pending(input_buffer);
|
||||
String rv = {
|
||||
.data = xmemdup(rbuffer_read_ptr(input_buffer), inbuf_size),
|
||||
.size = inbuf_size
|
||||
};
|
||||
rbuffer_consumed(input_buffer, inbuf_size);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/// Restore the contents of the input buffer and free `str`
|
||||
void input_buffer_restore(String str)
|
||||
{
|
||||
rbuffer_consumed(input_buffer, rbuffer_pending(input_buffer));
|
||||
rbuffer_write(input_buffer, str.data, str.size);
|
||||
free(str.data);
|
||||
}
|
||||
|
||||
size_t input_enqueue(String keys)
|
||||
{
|
||||
char *ptr = keys.data, *end = ptr + keys.size;
|
||||
|
||||
while (rbuffer_available(input_buffer) >= 6 && ptr < end) {
|
||||
uint8_t buf[6] = {0};
|
||||
unsigned int new_size = trans_special((uint8_t **)&ptr, buf, false);
|
||||
unsigned int new_size = trans_special((uint8_t **)&ptr, buf, true);
|
||||
|
||||
if (!new_size) {
|
||||
if (*ptr == '<') {
|
||||
@ -215,15 +177,19 @@ static unsigned int handle_mouse_event(char **ptr, uint8_t *buf,
|
||||
unsigned int bufsize)
|
||||
{
|
||||
int mouse_code = 0;
|
||||
int type = 0;
|
||||
|
||||
if (bufsize == 3) {
|
||||
mouse_code = buf[2];
|
||||
type = buf[1];
|
||||
} else if (bufsize == 6) {
|
||||
// prefixed with K_SPECIAL KS_MODIFIER mod
|
||||
mouse_code = buf[5];
|
||||
type = buf[4];
|
||||
}
|
||||
|
||||
if (!((mouse_code >= KE_LEFTMOUSE && mouse_code <= KE_RIGHTRELEASE)
|
||||
if (type != KS_EXTRA
|
||||
|| !((mouse_code >= KE_LEFTMOUSE && mouse_code <= KE_RIGHTRELEASE)
|
||||
|| (mouse_code >= KE_MOUSEDOWN && mouse_code <= KE_MOUSERIGHT))) {
|
||||
return bufsize;
|
||||
}
|
||||
@ -298,7 +264,7 @@ static bool input_poll(int ms)
|
||||
prof_inchar_enter();
|
||||
}
|
||||
|
||||
event_poll_until(ms, input_ready());
|
||||
event_poll_until(ms, input_ready() || eof);
|
||||
|
||||
if (do_profiling == PROF_YES && ms) {
|
||||
prof_inchar_exit();
|
||||
@ -307,96 +273,31 @@ static bool input_poll(int ms)
|
||||
return input_ready();
|
||||
}
|
||||
|
||||
void input_done(void)
|
||||
{
|
||||
eof = true;
|
||||
}
|
||||
|
||||
// This is a replacement for the old `WaitForChar` function in os_unix.c
|
||||
static InbufPollResult inbuf_poll(int ms)
|
||||
{
|
||||
if (typebuf_was_filled || rbuffer_pending(input_buffer)) {
|
||||
if (input_ready() || input_poll(ms)) {
|
||||
return kInputAvail;
|
||||
}
|
||||
|
||||
if (input_poll(ms)) {
|
||||
return eof && rstream_pending(read_stream) == 0 ?
|
||||
kInputEof :
|
||||
kInputAvail;
|
||||
}
|
||||
|
||||
return kInputNone;
|
||||
}
|
||||
|
||||
static void stderr_switch(void)
|
||||
{
|
||||
int mode = cur_tmode;
|
||||
// We probably set the wrong file descriptor to raw mode. Switch back to
|
||||
// cooked mode
|
||||
settmode(TMODE_COOK);
|
||||
// Stop the idle handle
|
||||
rstream_stop(read_stream);
|
||||
// Use stderr for stdin, also works for shell commands.
|
||||
read_cmd_fd = 2;
|
||||
// Initialize and start the input stream
|
||||
rstream_set_file(read_stream, read_cmd_fd);
|
||||
rstream_start(read_stream);
|
||||
// Set the mode back to what it was
|
||||
settmode(mode);
|
||||
return eof ? kInputEof : kInputNone;
|
||||
}
|
||||
|
||||
static void read_cb(RStream *rstream, void *data, bool at_eof)
|
||||
{
|
||||
if (at_eof) {
|
||||
if (!started_reading
|
||||
&& rstream_is_regular_file(rstream)
|
||||
&& os_isatty(STDERR_FILENO)) {
|
||||
// Read error. Since stderr is a tty we switch to reading from it. This
|
||||
// is for handling for cases like "foo | xargs vim" because xargs
|
||||
// redirects stdin from /dev/null. Previously, this was done in ui.c
|
||||
stderr_switch();
|
||||
} else {
|
||||
eof = true;
|
||||
}
|
||||
eof = true;
|
||||
}
|
||||
|
||||
convert_input();
|
||||
process_interrupts();
|
||||
started_reading = true;
|
||||
}
|
||||
|
||||
static void convert_input(void)
|
||||
{
|
||||
if (abstract_ui || !rbuffer_available(input_buffer)) {
|
||||
// No input buffer space
|
||||
return;
|
||||
}
|
||||
|
||||
bool convert = input_conv.vc_type != CONV_NONE;
|
||||
// Set unconverted data/length
|
||||
char *data = rbuffer_read_ptr(read_buffer);
|
||||
size_t data_length = rbuffer_pending(read_buffer);
|
||||
size_t converted_length = data_length;
|
||||
|
||||
if (convert) {
|
||||
// Perform input conversion according to `input_conv`
|
||||
size_t unconverted_length = 0;
|
||||
data = (char *)string_convert_ext(&input_conv,
|
||||
(uint8_t *)data,
|
||||
(int *)&converted_length,
|
||||
(int *)&unconverted_length);
|
||||
data_length -= unconverted_length;
|
||||
}
|
||||
|
||||
// The conversion code will be gone eventually, for now assume `input_buffer`
|
||||
// always has space for the converted data(it's many times the size of
|
||||
// `read_buffer`, so it's hard to imagine a scenario where the converted data
|
||||
// doesn't fit)
|
||||
assert(converted_length <= rbuffer_available(input_buffer));
|
||||
// Write processed data to input buffer.
|
||||
(void)rbuffer_write(input_buffer, data, converted_length);
|
||||
// Adjust raw buffer pointers
|
||||
rbuffer_consumed(read_buffer, data_length);
|
||||
|
||||
if (convert) {
|
||||
// data points to memory allocated by `string_convert_ext`, free it.
|
||||
free(data);
|
||||
}
|
||||
char *buf = rbuffer_read_ptr(read_buffer);
|
||||
size_t buf_size = rbuffer_pending(read_buffer);
|
||||
(void)rbuffer_write(input_buffer, buf, buf_size);
|
||||
rbuffer_consumed(read_buffer, buf_size);
|
||||
}
|
||||
|
||||
static void process_interrupts(void)
|
||||
@ -440,9 +341,8 @@ static int push_event_key(uint8_t *buf, int maxlen)
|
||||
static bool input_ready(void)
|
||||
{
|
||||
return typebuf_was_filled || // API call filled typeahead
|
||||
rbuffer_pending(input_buffer) > 0 || // Stdin input
|
||||
event_has_deferred() || // Events must be processed
|
||||
(!abstract_ui && eof); // Stdin closed
|
||||
rbuffer_pending(input_buffer) > 0 || // Input buffer filled
|
||||
event_has_deferred(); // Events must be processed
|
||||
}
|
||||
|
||||
// Exit because of an input read error.
|
||||
|
@ -271,15 +271,6 @@ void rstream_set_file(RStream *rstream, uv_file file)
|
||||
rstream->free_handle = true;
|
||||
}
|
||||
|
||||
/// Tests if the stream is backed by a regular file
|
||||
///
|
||||
/// @param rstream The `RStream` instance
|
||||
/// @return True if the underlying file descriptor represents a regular file
|
||||
bool rstream_is_regular_file(RStream *rstream)
|
||||
{
|
||||
return rstream->file_type == UV_FILE;
|
||||
}
|
||||
|
||||
/// Starts watching for events from a `RStream` instance.
|
||||
///
|
||||
/// @param rstream The `RStream` instance
|
||||
|
@ -20,7 +20,7 @@
|
||||
KMEMPOOL_INIT(SignalEventPool, int, SignalEventFreer)
|
||||
kmempool_t(SignalEventPool) *signal_event_pool = NULL;
|
||||
|
||||
static uv_signal_t sint, spipe, shup, squit, sterm, swinch;
|
||||
static uv_signal_t spipe, shup, squit, sterm;
|
||||
#ifdef SIGPWR
|
||||
static uv_signal_t spwr;
|
||||
#endif
|
||||
@ -30,24 +30,18 @@ static bool rejecting_deadly;
|
||||
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
||||
# include "os/signal.c.generated.h"
|
||||
#endif
|
||||
|
||||
void signal_init(void)
|
||||
{
|
||||
signal_event_pool = kmp_init(SignalEventPool);
|
||||
uv_signal_init(uv_default_loop(), &sint);
|
||||
uv_signal_init(uv_default_loop(), &spipe);
|
||||
uv_signal_init(uv_default_loop(), &shup);
|
||||
uv_signal_init(uv_default_loop(), &squit);
|
||||
uv_signal_init(uv_default_loop(), &sterm);
|
||||
uv_signal_init(uv_default_loop(), &swinch);
|
||||
uv_signal_start(&sint, signal_cb, SIGINT);
|
||||
uv_signal_start(&spipe, signal_cb, SIGPIPE);
|
||||
uv_signal_start(&shup, signal_cb, SIGHUP);
|
||||
uv_signal_start(&squit, signal_cb, SIGQUIT);
|
||||
uv_signal_start(&sterm, signal_cb, SIGTERM);
|
||||
if (!abstract_ui) {
|
||||
// TODO(tarruda): There must be an API function for resizing window
|
||||
uv_signal_start(&swinch, signal_cb, SIGWINCH);
|
||||
}
|
||||
#ifdef SIGPWR
|
||||
uv_signal_init(uv_default_loop(), &spwr);
|
||||
uv_signal_start(&spwr, signal_cb, SIGPWR);
|
||||
@ -57,12 +51,10 @@ void signal_init(void)
|
||||
void signal_teardown(void)
|
||||
{
|
||||
signal_stop();
|
||||
uv_close((uv_handle_t *)&sint, NULL);
|
||||
uv_close((uv_handle_t *)&spipe, NULL);
|
||||
uv_close((uv_handle_t *)&shup, NULL);
|
||||
uv_close((uv_handle_t *)&squit, NULL);
|
||||
uv_close((uv_handle_t *)&sterm, NULL);
|
||||
uv_close((uv_handle_t *)&swinch, NULL);
|
||||
#ifdef SIGPWR
|
||||
uv_close((uv_handle_t *)&spwr, NULL);
|
||||
#endif
|
||||
@ -70,12 +62,10 @@ void signal_teardown(void)
|
||||
|
||||
void signal_stop(void)
|
||||
{
|
||||
uv_signal_stop(&sint);
|
||||
uv_signal_stop(&spipe);
|
||||
uv_signal_stop(&shup);
|
||||
uv_signal_stop(&squit);
|
||||
uv_signal_stop(&sterm);
|
||||
uv_signal_stop(&swinch);
|
||||
#ifdef SIGPWR
|
||||
uv_signal_stop(&spwr);
|
||||
#endif
|
||||
@ -94,16 +84,12 @@ void signal_accept_deadly(void)
|
||||
static char * signal_name(int signum)
|
||||
{
|
||||
switch (signum) {
|
||||
case SIGINT:
|
||||
return "SIGINT";
|
||||
#ifdef SIGPWR
|
||||
case SIGPWR:
|
||||
return "SIGPWR";
|
||||
#endif
|
||||
case SIGPIPE:
|
||||
return "SIGPIPE";
|
||||
case SIGWINCH:
|
||||
return "SIGWINCH";
|
||||
case SIGTERM:
|
||||
return "SIGTERM";
|
||||
case SIGQUIT:
|
||||
@ -148,9 +134,6 @@ static void on_signal_event(Event event)
|
||||
kmp_free(SignalEventPool, signal_event_pool, event.data);
|
||||
|
||||
switch (signum) {
|
||||
case SIGINT:
|
||||
got_int = true;
|
||||
break;
|
||||
#ifdef SIGPWR
|
||||
case SIGPWR:
|
||||
// Signal of a power failure(eg batteries low), flush the swap files to
|
||||
@ -161,9 +144,6 @@ static void on_signal_event(Event event)
|
||||
case SIGPIPE:
|
||||
// Ignore
|
||||
break;
|
||||
case SIGWINCH:
|
||||
shell_resized();
|
||||
break;
|
||||
case SIGTERM:
|
||||
case SIGQUIT:
|
||||
case SIGHUP:
|
||||
|
@ -56,18 +56,10 @@
|
||||
#include "nvim/msgpack_rpc/helpers.h"
|
||||
#include "nvim/msgpack_rpc/defs.h"
|
||||
|
||||
#if defined(HAVE_SYS_IOCTL_H)
|
||||
# include <sys/ioctl.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STROPTS_H
|
||||
# include <stropts.h>
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_TERMIOS_H)
|
||||
# include <termios.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SELINUX
|
||||
# include <selinux/selinux.h>
|
||||
static int selinux_enabled = -1;
|
||||
@ -82,53 +74,6 @@ static int did_set_title = FALSE;
|
||||
static char_u *oldicon = NULL;
|
||||
static int did_set_icon = FALSE;
|
||||
|
||||
/*
|
||||
* If the machine has job control, use it to suspend the program,
|
||||
* otherwise fake it by starting a new shell.
|
||||
*/
|
||||
void mch_suspend(void)
|
||||
{
|
||||
#if defined(SIGTSTP)
|
||||
out_flush(); /* needed to make cursor visible on some systems */
|
||||
settmode(TMODE_COOK);
|
||||
out_flush(); /* needed to disable mouse on some systems */
|
||||
|
||||
// Note: compiler defines _REENTRANT when given -pthread flag.
|
||||
# if defined(_REENTRANT) && defined(SIGCONT)
|
||||
sigcont_received = FALSE;
|
||||
# endif
|
||||
uv_kill(0, SIGTSTP); // send ourselves a STOP signal
|
||||
# if defined(_REENTRANT) && defined(SIGCONT)
|
||||
/*
|
||||
* Wait for the SIGCONT signal to be handled. It generally happens
|
||||
* immediately, but somehow not all the time. Do not call pause()
|
||||
* because there would be race condition which would hang Vim if
|
||||
* signal happened in between the test of sigcont_received and the
|
||||
* call to pause(). If signal is not yet received, call sleep(0)
|
||||
* to just yield CPU. Signal should then be received. If somehow
|
||||
* it's still not received, sleep 1, 2, 3 ms. Don't bother waiting
|
||||
* further if signal is not received after 1+2+3+4 ms (not expected
|
||||
* to happen).
|
||||
*/
|
||||
{
|
||||
long wait_time;
|
||||
for (wait_time = 0; !sigcont_received && wait_time <= 3L; wait_time++)
|
||||
/* Loop is not entered most of the time */
|
||||
os_delay(wait_time, false);
|
||||
}
|
||||
# endif
|
||||
|
||||
/*
|
||||
* Set oldtitle to NULL, so the current title is obtained again.
|
||||
*/
|
||||
free(oldtitle);
|
||||
oldtitle = NULL;
|
||||
settmode(TMODE_RAW);
|
||||
need_check_timestamps = TRUE;
|
||||
did_check_timestamps = FALSE;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int get_x11_title(int test_only)
|
||||
{
|
||||
return FALSE;
|
||||
@ -161,7 +106,6 @@ int mch_can_restore_icon(void)
|
||||
*/
|
||||
void mch_settitle(char_u *title, char_u *icon)
|
||||
{
|
||||
int type = 0;
|
||||
static int recursive = 0;
|
||||
|
||||
if (T_NAME == NULL) /* no terminal name (yet) */
|
||||
@ -175,39 +119,13 @@ void mch_settitle(char_u *title, char_u *icon)
|
||||
return;
|
||||
++recursive;
|
||||
|
||||
/*
|
||||
* if the window ID and the display is known, we may use X11 calls
|
||||
*/
|
||||
|
||||
/*
|
||||
* Note: if "t_ts" is set, title is set with escape sequence rather
|
||||
* than x11 calls, because the x11 calls don't always work
|
||||
*/
|
||||
if ((type || *T_TS != NUL || abstract_ui) && title != NULL) {
|
||||
if (oldtitle == NULL
|
||||
) /* first call but not in GUI, save title */
|
||||
(void)get_x11_title(FALSE);
|
||||
|
||||
if (abstract_ui) {
|
||||
ui_set_title((char *)title);
|
||||
} else if (*T_TS != NUL) /* it's OK if t_fs is empty */
|
||||
term_settitle(title);
|
||||
if (title != NULL) {
|
||||
ui_set_title((char *)title);
|
||||
did_set_title = TRUE;
|
||||
}
|
||||
|
||||
if ((type || *T_CIS != NUL || abstract_ui) && icon != NULL) {
|
||||
if (oldicon == NULL
|
||||
) /* first call, save icon */
|
||||
get_x11_icon(FALSE);
|
||||
|
||||
if (abstract_ui) {
|
||||
ui_set_icon((char *)icon);
|
||||
} else if (*T_CIS != NUL) {
|
||||
out_str(T_CIS); /* set icon start */
|
||||
out_str_nf(icon);
|
||||
out_str(T_CIE); /* set icon end */
|
||||
out_flush();
|
||||
}
|
||||
if (icon != NULL) {
|
||||
ui_set_icon((char *)icon);
|
||||
did_set_icon = TRUE;
|
||||
}
|
||||
--recursive;
|
||||
@ -245,17 +163,6 @@ int vim_is_xterm(char_u *name)
|
||||
|| STRCMP(name, "builtin_xterm") == 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return TRUE if "name" appears to be that of a terminal
|
||||
* known to support the xterm-style mouse protocol.
|
||||
* Relies on term_is_xterm having been set to its correct value.
|
||||
*/
|
||||
int use_xterm_like_mouse(char_u *name)
|
||||
{
|
||||
return name != NULL
|
||||
&& (term_is_xterm || STRNICMP(name, "screen", 6) == 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return non-zero when using an xterm mouse, according to 'ttymouse'.
|
||||
* Return 1 for "xterm".
|
||||
@ -481,7 +388,6 @@ void mch_exit(int r)
|
||||
exiting = TRUE;
|
||||
|
||||
{
|
||||
settmode(TMODE_COOK);
|
||||
mch_restore_title(3); /* restore xterm title and icon name */
|
||||
/*
|
||||
* When t_ti is not empty but it doesn't cause swapping terminal
|
||||
@ -492,9 +398,7 @@ void mch_exit(int r)
|
||||
if (swapping_screen() && !newline_on_exit)
|
||||
exit_scroll();
|
||||
|
||||
/* Stop termcap: May need to check for T_CRV response, which
|
||||
* requires RAW mode. */
|
||||
stoptermcap();
|
||||
ui_builtin_stop();
|
||||
|
||||
/*
|
||||
* A newline is only required after a message in the alternate screen.
|
||||
@ -524,143 +428,6 @@ void mch_exit(int r)
|
||||
exit(r);
|
||||
}
|
||||
|
||||
void mch_settmode(int tmode)
|
||||
{
|
||||
static int first = TRUE;
|
||||
|
||||
#if defined(ECHOE) && defined(ICANON) && (defined(HAVE_TERMIO_H) || \
|
||||
defined(HAVE_TERMIOS_H))
|
||||
/*
|
||||
* for "new" tty systems
|
||||
*/
|
||||
# ifdef HAVE_TERMIOS_H
|
||||
static struct termios told;
|
||||
struct termios tnew;
|
||||
# else
|
||||
static struct termio told;
|
||||
struct termio tnew;
|
||||
# endif
|
||||
|
||||
if (first) {
|
||||
first = FALSE;
|
||||
# if defined(HAVE_TERMIOS_H)
|
||||
tcgetattr(read_cmd_fd, &told);
|
||||
# else
|
||||
ioctl(read_cmd_fd, TCGETA, &told);
|
||||
# endif
|
||||
}
|
||||
|
||||
tnew = told;
|
||||
if (tmode == TMODE_RAW) {
|
||||
/*
|
||||
* ~ICRNL enables typing ^V^M
|
||||
*/
|
||||
tnew.c_iflag &= ~ICRNL;
|
||||
tnew.c_lflag &= ~(ICANON | ECHO | ISIG | ECHOE
|
||||
# if defined(IEXTEN)
|
||||
| IEXTEN /* IEXTEN enables typing ^V on SOLARIS */
|
||||
# endif
|
||||
);
|
||||
# ifdef ONLCR /* don't map NL -> CR NL, we do it ourselves */
|
||||
tnew.c_oflag &= ~ONLCR;
|
||||
# endif
|
||||
tnew.c_cc[VMIN] = 1; /* return after 1 char */
|
||||
tnew.c_cc[VTIME] = 0; /* don't wait */
|
||||
} else if (tmode == TMODE_SLEEP)
|
||||
tnew.c_lflag &= ~(ECHO);
|
||||
|
||||
# if defined(HAVE_TERMIOS_H)
|
||||
{
|
||||
int n = 10;
|
||||
|
||||
/* A signal may cause tcsetattr() to fail (e.g., SIGCONT). Retry a
|
||||
* few times. */
|
||||
while (tcsetattr(read_cmd_fd, TCSANOW, &tnew) == -1
|
||||
&& errno == EINTR && n > 0)
|
||||
--n;
|
||||
}
|
||||
# else
|
||||
ioctl(read_cmd_fd, TCSETA, &tnew);
|
||||
# endif
|
||||
|
||||
#else
|
||||
|
||||
/*
|
||||
* for "old" tty systems
|
||||
*/
|
||||
# ifndef TIOCSETN
|
||||
# define TIOCSETN TIOCSETP /* for hpux 9.0 */
|
||||
# endif
|
||||
static struct sgttyb ttybold;
|
||||
struct sgttyb ttybnew;
|
||||
|
||||
if (first) {
|
||||
first = FALSE;
|
||||
ioctl(read_cmd_fd, TIOCGETP, &ttybold);
|
||||
}
|
||||
|
||||
ttybnew = ttybold;
|
||||
if (tmode == TMODE_RAW) {
|
||||
ttybnew.sg_flags &= ~(CRMOD | ECHO);
|
||||
ttybnew.sg_flags |= RAW;
|
||||
} else if (tmode == TMODE_SLEEP)
|
||||
ttybnew.sg_flags &= ~(ECHO);
|
||||
ioctl(read_cmd_fd, TIOCSETN, &ttybnew);
|
||||
#endif
|
||||
curr_tmode = tmode;
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to get the code for "t_kb" from the stty setting
|
||||
*
|
||||
* Even if termcap claims a backspace key, the user's setting *should*
|
||||
* prevail. stty knows more about reality than termcap does, and if
|
||||
* somebody's usual erase key is DEL (which, for most BSD users, it will
|
||||
* be), they're going to get really annoyed if their erase key starts
|
||||
* doing forward deletes for no reason. (Eric Fischer)
|
||||
*/
|
||||
void get_stty(void)
|
||||
{
|
||||
char_u buf[2];
|
||||
char_u *p;
|
||||
|
||||
#if defined(ECHOE) && defined(ICANON) && (defined(HAVE_TERMIO_H) || \
|
||||
defined(HAVE_TERMIOS_H))
|
||||
/* for "new" tty systems */
|
||||
# ifdef HAVE_TERMIOS_H
|
||||
struct termios keys;
|
||||
# else
|
||||
struct termio keys;
|
||||
# endif
|
||||
|
||||
# if defined(HAVE_TERMIOS_H)
|
||||
if (tcgetattr(read_cmd_fd, &keys) != -1)
|
||||
# else
|
||||
if (ioctl(read_cmd_fd, TCGETA, &keys) != -1)
|
||||
# endif
|
||||
{
|
||||
buf[0] = keys.c_cc[VERASE];
|
||||
intr_char = keys.c_cc[VINTR];
|
||||
#else
|
||||
/* for "old" tty systems */
|
||||
struct sgttyb keys;
|
||||
|
||||
if (ioctl(read_cmd_fd, TIOCGETP, &keys) != -1) {
|
||||
buf[0] = keys.sg_erase;
|
||||
intr_char = keys.sg_kill;
|
||||
#endif
|
||||
buf[1] = NUL;
|
||||
add_termcode((char_u *)"kb", buf, FALSE);
|
||||
|
||||
/*
|
||||
* If <BS> and <DEL> are now the same, redefine <DEL>.
|
||||
*/
|
||||
p = find_termcode((char_u *)"kD");
|
||||
if (p != NULL && p[0] == buf[0] && p[1] == buf[1])
|
||||
do_fixdel(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Set mouse clicks on or off.
|
||||
*/
|
||||
@ -712,173 +479,6 @@ void mch_setmouse(int on)
|
||||
|
||||
}
|
||||
|
||||
/// Sets the mouse termcode, depending on the 'term' and 'ttymouse' options.
|
||||
void check_mouse_termcode(void)
|
||||
{
|
||||
xterm_conflict_mouse = false;
|
||||
|
||||
if (use_xterm_mouse()
|
||||
&& use_xterm_mouse() != 3
|
||||
) {
|
||||
set_mouse_termcode(KS_MOUSE, (char_u *)(term_is_8bit(T_NAME)
|
||||
? "\233M"
|
||||
: "\033[M"));
|
||||
if (*p_mouse != NUL) {
|
||||
/* force mouse off and maybe on to send possibly new mouse
|
||||
* activation sequence to the xterm, with(out) drag tracing. */
|
||||
mch_setmouse(FALSE);
|
||||
setmouse();
|
||||
}
|
||||
} else
|
||||
del_mouse_termcode(KS_MOUSE);
|
||||
|
||||
|
||||
/* There is no conflict, but one may type "ESC }" from Insert mode. Don't
|
||||
* define it in the GUI or when using an xterm. */
|
||||
if (!use_xterm_mouse()
|
||||
)
|
||||
set_mouse_termcode(KS_NETTERM_MOUSE,
|
||||
(char_u *)"\033}");
|
||||
else
|
||||
del_mouse_termcode(KS_NETTERM_MOUSE);
|
||||
|
||||
// Conflicts with xterm mouse: "\033[" and "\033[M".
|
||||
// Also conflicts with the xterm termresponse, skip this if it was requested
|
||||
// already.
|
||||
if (!use_xterm_mouse()) {
|
||||
set_mouse_termcode(KS_DEC_MOUSE, (char_u *)(term_is_8bit(T_NAME)
|
||||
? "\233" : "\033["));
|
||||
xterm_conflict_mouse = true;
|
||||
}
|
||||
else {
|
||||
del_mouse_termcode(KS_DEC_MOUSE);
|
||||
}
|
||||
/* same as the dec mouse */
|
||||
if (use_xterm_mouse() == 3 && !did_request_esc_sequence()) {
|
||||
set_mouse_termcode(KS_URXVT_MOUSE,
|
||||
(char_u *)(term_is_8bit(T_NAME) ? "\233" : "\033["));
|
||||
if (*p_mouse != NUL) {
|
||||
mch_setmouse(false);
|
||||
setmouse();
|
||||
}
|
||||
resume_get_esc_sequence();
|
||||
} else {
|
||||
del_mouse_termcode(KS_URXVT_MOUSE);
|
||||
}
|
||||
// There is no conflict with xterm mouse.
|
||||
if (use_xterm_mouse() == 4) {
|
||||
set_mouse_termcode(KS_SGR_MOUSE, (char_u *)(term_is_8bit(T_NAME)
|
||||
? "\233<"
|
||||
: "\033[<"));
|
||||
|
||||
if (*p_mouse != NUL) {
|
||||
mch_setmouse(FALSE);
|
||||
setmouse();
|
||||
}
|
||||
} else {
|
||||
del_mouse_termcode(KS_SGR_MOUSE);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to get the current window size:
|
||||
* 1. with an ioctl(), most accurate method
|
||||
* 2. from the environment variables LINES and COLUMNS
|
||||
* 3. from the termcap
|
||||
* 4. keep using the old values
|
||||
* Return OK when size could be determined, FAIL otherwise.
|
||||
*/
|
||||
int mch_get_shellsize(void)
|
||||
{
|
||||
long rows = 0;
|
||||
long columns = 0;
|
||||
char_u *p;
|
||||
|
||||
/*
|
||||
* 1. try using an ioctl. It is the most accurate method.
|
||||
*
|
||||
* Try using TIOCGWINSZ first, some systems that have it also define
|
||||
* TIOCGSIZE but don't have a struct ttysize.
|
||||
*/
|
||||
# ifdef TIOCGWINSZ
|
||||
{
|
||||
struct winsize ws;
|
||||
int fd = 1;
|
||||
|
||||
/* When stdout is not a tty, use stdin for the ioctl(). */
|
||||
if (!isatty(fd) && isatty(read_cmd_fd))
|
||||
fd = read_cmd_fd;
|
||||
if (ioctl(fd, TIOCGWINSZ, &ws) == 0) {
|
||||
columns = ws.ws_col;
|
||||
rows = ws.ws_row;
|
||||
}
|
||||
}
|
||||
# else /* TIOCGWINSZ */
|
||||
# ifdef TIOCGSIZE
|
||||
{
|
||||
struct ttysize ts;
|
||||
int fd = 1;
|
||||
|
||||
/* When stdout is not a tty, use stdin for the ioctl(). */
|
||||
if (!isatty(fd) && isatty(read_cmd_fd))
|
||||
fd = read_cmd_fd;
|
||||
if (ioctl(fd, TIOCGSIZE, &ts) == 0) {
|
||||
columns = ts.ts_cols;
|
||||
rows = ts.ts_lines;
|
||||
}
|
||||
}
|
||||
# endif /* TIOCGSIZE */
|
||||
# endif /* TIOCGWINSZ */
|
||||
|
||||
/*
|
||||
* 2. get size from environment
|
||||
* When being POSIX compliant ('|' flag in 'cpoptions') this overrules
|
||||
* the ioctl() values!
|
||||
*/
|
||||
if (columns == 0 || rows == 0 || vim_strchr(p_cpo, CPO_TSIZE) != NULL) {
|
||||
if ((p = (char_u *)os_getenv("LINES")))
|
||||
rows = atoi((char *)p);
|
||||
if ((p = (char_u *)os_getenv("COLUMNS")))
|
||||
columns = atoi((char *)p);
|
||||
}
|
||||
|
||||
#ifdef HAVE_TGETENT
|
||||
/*
|
||||
* 3. try reading "co" and "li" entries from termcap
|
||||
*/
|
||||
if (columns == 0 || rows == 0)
|
||||
getlinecol(&columns, &rows);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 4. If everything fails, use the old values
|
||||
*/
|
||||
if (columns <= 0 || rows <= 0)
|
||||
return FAIL;
|
||||
|
||||
Rows = rows;
|
||||
Columns = columns;
|
||||
limit_screen_size();
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to set the window size to Rows and Columns.
|
||||
*/
|
||||
void mch_set_shellsize(void)
|
||||
{
|
||||
if (*T_CWS) {
|
||||
/*
|
||||
* NOTE: if you get an error here that term_set_winsize() is
|
||||
* undefined, check the output of configure. It could probably not
|
||||
* find a ncurses, termcap or termlib library.
|
||||
*/
|
||||
term_set_winsize((int)Rows, (int)Columns);
|
||||
out_flush();
|
||||
screen_start(); /* don't know where cursor is now */
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* mch_expand_wildcards() - this code does wild-card pattern matching using
|
||||
* the shell
|
||||
|
@ -231,119 +231,6 @@ void redraw_buf_later(buf_T *buf, int type)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Redraw as soon as possible. When the command line is not scrolled redraw
|
||||
* right away and restore what was on the command line.
|
||||
* Return a code indicating what happened.
|
||||
*/
|
||||
int redraw_asap(int type)
|
||||
{
|
||||
int rows;
|
||||
int r;
|
||||
int ret = 0;
|
||||
schar_T *screenline; /* copy from ScreenLines[] */
|
||||
sattr_T *screenattr; /* copy from ScreenAttrs[] */
|
||||
int i;
|
||||
u8char_T *screenlineUC = NULL; /* copy from ScreenLinesUC[] */
|
||||
u8char_T *screenlineC[MAX_MCO]; /* copy from ScreenLinesC[][] */
|
||||
schar_T *screenline2 = NULL; /* copy from ScreenLines2[] */
|
||||
const bool l_enc_utf8 = enc_utf8;
|
||||
const int l_enc_dbcs = enc_dbcs;
|
||||
const long l_p_mco = p_mco;
|
||||
|
||||
redraw_later(type);
|
||||
if (msg_scrolled || (State != NORMAL && State != NORMAL_BUSY))
|
||||
return ret;
|
||||
|
||||
/* Allocate space to save the text displayed in the command line area. */
|
||||
rows = Rows - cmdline_row;
|
||||
screenline = xmalloc((size_t)(rows * Columns * sizeof(schar_T)));
|
||||
screenattr = xmalloc((size_t)(rows * Columns * sizeof(sattr_T)));
|
||||
|
||||
if (l_enc_utf8) {
|
||||
screenlineUC = xmalloc((size_t)(rows * Columns * sizeof(u8char_T)));
|
||||
|
||||
for (i = 0; i < l_p_mco; ++i) {
|
||||
screenlineC[i] = xmalloc((size_t)(rows * Columns * sizeof(u8char_T)));
|
||||
}
|
||||
}
|
||||
if (l_enc_dbcs == DBCS_JPNU) {
|
||||
screenline2 = xmalloc((size_t)(rows * Columns * sizeof(schar_T)));
|
||||
}
|
||||
|
||||
/* Save the text displayed in the command line area. */
|
||||
for (r = 0; r < rows; ++r) {
|
||||
memmove(screenline + r * Columns,
|
||||
ScreenLines + LineOffset[cmdline_row + r],
|
||||
(size_t)Columns * sizeof(schar_T));
|
||||
memmove(screenattr + r * Columns,
|
||||
ScreenAttrs + LineOffset[cmdline_row + r],
|
||||
(size_t)Columns * sizeof(sattr_T));
|
||||
if (l_enc_utf8) {
|
||||
memmove(screenlineUC + r * Columns,
|
||||
ScreenLinesUC + LineOffset[cmdline_row + r],
|
||||
(size_t)Columns * sizeof(u8char_T));
|
||||
for (i = 0; i < l_p_mco; ++i)
|
||||
memmove(screenlineC[i] + r * Columns,
|
||||
ScreenLinesC[r] + LineOffset[cmdline_row + r],
|
||||
(size_t)Columns * sizeof(u8char_T));
|
||||
}
|
||||
if (l_enc_dbcs == DBCS_JPNU)
|
||||
memmove(screenline2 + r * Columns,
|
||||
ScreenLines2 + LineOffset[cmdline_row + r],
|
||||
(size_t)Columns * sizeof(schar_T));
|
||||
}
|
||||
|
||||
update_screen(0);
|
||||
ret = 3;
|
||||
|
||||
if (must_redraw == 0) {
|
||||
int off = (int)(current_ScreenLine - ScreenLines);
|
||||
|
||||
/* Restore the text displayed in the command line area. */
|
||||
for (r = 0; r < rows; ++r) {
|
||||
memmove(current_ScreenLine,
|
||||
screenline + r * Columns,
|
||||
(size_t)Columns * sizeof(schar_T));
|
||||
memmove(ScreenAttrs + off,
|
||||
screenattr + r * Columns,
|
||||
(size_t)Columns * sizeof(sattr_T));
|
||||
if (l_enc_utf8) {
|
||||
memmove(ScreenLinesUC + off,
|
||||
screenlineUC + r * Columns,
|
||||
(size_t)Columns * sizeof(u8char_T));
|
||||
for (i = 0; i < l_p_mco; ++i)
|
||||
memmove(ScreenLinesC[i] + off,
|
||||
screenlineC[i] + r * Columns,
|
||||
(size_t)Columns * sizeof(u8char_T));
|
||||
}
|
||||
if (l_enc_dbcs == DBCS_JPNU)
|
||||
memmove(ScreenLines2 + off,
|
||||
screenline2 + r * Columns,
|
||||
(size_t)Columns * sizeof(schar_T));
|
||||
SCREEN_LINE(cmdline_row + r, 0, Columns, Columns, FALSE);
|
||||
}
|
||||
ret = 4;
|
||||
}
|
||||
|
||||
free(screenline);
|
||||
free(screenattr);
|
||||
if (l_enc_utf8) {
|
||||
free(screenlineUC);
|
||||
for (i = 0; i < l_p_mco; ++i)
|
||||
free(screenlineC[i]);
|
||||
}
|
||||
if (l_enc_dbcs == DBCS_JPNU)
|
||||
free(screenline2);
|
||||
|
||||
/* Show the intro message when appropriate. */
|
||||
maybe_intro_message();
|
||||
|
||||
setcursor();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Changed something in the current window, at buffer line "lnum", that
|
||||
* requires that line and possibly other lines to be redrawn.
|
||||
@ -4472,23 +4359,6 @@ static void screen_line(int row, int coloff, int endcol, int clear_width, int rl
|
||||
if (char_cells == 2)
|
||||
ScreenLines[off_to + 1] = ScreenLines[off_from + 1];
|
||||
|
||||
#if defined(FEAT_GUI) || defined(UNIX)
|
||||
/* The bold trick makes a single column of pixels appear in the
|
||||
* next character. When a bold character is removed, the next
|
||||
* character should be redrawn too. This happens for our own GUI
|
||||
* and for some xterms. */
|
||||
if (
|
||||
# ifdef UNIX
|
||||
term_is_xterm
|
||||
# endif
|
||||
) {
|
||||
hl = ScreenAttrs[off_to];
|
||||
if (hl > HL_ALL)
|
||||
hl = syn_attr2attr(hl);
|
||||
if (hl & HL_BOLD)
|
||||
redraw_next = TRUE;
|
||||
}
|
||||
#endif
|
||||
ScreenAttrs[off_to] = ScreenAttrs[off_from];
|
||||
/* For simplicity set the attributes of second half of a
|
||||
* double-wide character equal to the first half. */
|
||||
@ -5456,24 +5326,6 @@ void screen_puts_len(char_u *text, int textlen, int row, int col, int attr)
|
||||
if (need_redraw
|
||||
|| force_redraw_this
|
||||
) {
|
||||
#if defined(FEAT_GUI) || defined(UNIX)
|
||||
/* The bold trick makes a single row of pixels appear in the next
|
||||
* character. When a bold character is removed, the next
|
||||
* character should be redrawn too. This happens for our own GUI
|
||||
* and for some xterms. */
|
||||
if (need_redraw && ScreenLines[off] != ' ' && (
|
||||
# ifdef UNIX
|
||||
term_is_xterm
|
||||
# endif
|
||||
)) {
|
||||
int n = ScreenAttrs[off];
|
||||
|
||||
if (n > HL_ALL)
|
||||
n = syn_attr2attr(n);
|
||||
if (n & HL_BOLD)
|
||||
force_redraw_next = TRUE;
|
||||
}
|
||||
#endif
|
||||
/* When at the end of the text and overwriting a two-cell
|
||||
* character with a one-cell character, need to clear the next
|
||||
* cell. Also when overwriting the left halve of a two-cell char
|
||||
@ -5837,156 +5689,25 @@ next_search_hl_pos(
|
||||
|
||||
static void screen_start_highlight(int attr)
|
||||
{
|
||||
attrentry_T *aep = NULL;
|
||||
|
||||
screen_attr = attr;
|
||||
if (full_screen) {
|
||||
if (abstract_ui) {
|
||||
char buf[20];
|
||||
sprintf(buf, "\033|%dh", attr);
|
||||
OUT_STR(buf);
|
||||
} else {
|
||||
if (attr > HL_ALL) { /* special HL attr. */
|
||||
if (t_colors > 1)
|
||||
aep = syn_cterm_attr2entry(attr);
|
||||
else
|
||||
aep = syn_term_attr2entry(attr);
|
||||
if (aep == NULL) /* did ":syntax clear" */
|
||||
attr = 0;
|
||||
else
|
||||
attr = aep->ae_attr;
|
||||
}
|
||||
if ((attr & HL_BOLD) && T_MD != NULL) /* bold */
|
||||
out_str(T_MD);
|
||||
else if (aep != NULL && t_colors > 1 && aep->ae_u.cterm.fg_color
|
||||
&& cterm_normal_fg_bold)
|
||||
/* If the Normal FG color has BOLD attribute and the new HL
|
||||
* has a FG color defined, clear BOLD. */
|
||||
out_str(T_ME);
|
||||
if ((attr & HL_STANDOUT) && T_SO != NULL) /* standout */
|
||||
out_str(T_SO);
|
||||
if ((attr & (HL_UNDERLINE | HL_UNDERCURL)) && T_US != NULL)
|
||||
/* underline or undercurl */
|
||||
out_str(T_US);
|
||||
if ((attr & HL_ITALIC) && T_CZH != NULL) /* italic */
|
||||
out_str(T_CZH);
|
||||
if ((attr & HL_INVERSE) && T_MR != NULL) /* inverse (reverse) */
|
||||
out_str(T_MR);
|
||||
|
||||
/*
|
||||
* Output the color or start string after bold etc., in case the
|
||||
* bold etc. override the color setting.
|
||||
*/
|
||||
if (aep != NULL) {
|
||||
if (t_colors > 1) {
|
||||
if (aep->ae_u.cterm.fg_color)
|
||||
term_fg_color(aep->ae_u.cterm.fg_color - 1);
|
||||
if (aep->ae_u.cterm.bg_color)
|
||||
term_bg_color(aep->ae_u.cterm.bg_color - 1);
|
||||
} else {
|
||||
if (aep->ae_u.term.start != NULL)
|
||||
out_str(aep->ae_u.term.start);
|
||||
}
|
||||
}
|
||||
}
|
||||
char buf[20];
|
||||
sprintf(buf, "\033|%dh", attr);
|
||||
OUT_STR(buf);
|
||||
}
|
||||
}
|
||||
|
||||
void screen_stop_highlight(void)
|
||||
{
|
||||
int do_ME = FALSE; /* output T_ME code */
|
||||
|
||||
if (screen_attr != 0) {
|
||||
if (abstract_ui) {
|
||||
// Handled in ui.c
|
||||
char buf[20];
|
||||
sprintf(buf, "\033|%dH", screen_attr);
|
||||
OUT_STR(buf);
|
||||
} else {
|
||||
if (screen_attr > HL_ALL) { /* special HL attr. */
|
||||
attrentry_T *aep;
|
||||
|
||||
if (t_colors > 1) {
|
||||
/*
|
||||
* Assume that t_me restores the original colors!
|
||||
*/
|
||||
aep = syn_cterm_attr2entry(screen_attr);
|
||||
if (aep != NULL && (aep->ae_u.cterm.fg_color
|
||||
|| aep->ae_u.cterm.bg_color))
|
||||
do_ME = TRUE;
|
||||
} else {
|
||||
aep = syn_term_attr2entry(screen_attr);
|
||||
if (aep != NULL && aep->ae_u.term.stop != NULL) {
|
||||
if (STRCMP(aep->ae_u.term.stop, T_ME) == 0)
|
||||
do_ME = TRUE;
|
||||
else
|
||||
out_str(aep->ae_u.term.stop);
|
||||
}
|
||||
}
|
||||
if (aep == NULL) /* did ":syntax clear" */
|
||||
screen_attr = 0;
|
||||
else
|
||||
screen_attr = aep->ae_attr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Often all ending-codes are equal to T_ME. Avoid outputting the
|
||||
* same sequence several times.
|
||||
*/
|
||||
if (screen_attr & HL_STANDOUT) {
|
||||
if (STRCMP(T_SE, T_ME) == 0)
|
||||
do_ME = TRUE;
|
||||
else
|
||||
out_str(T_SE);
|
||||
}
|
||||
if (screen_attr & (HL_UNDERLINE | HL_UNDERCURL)) {
|
||||
if (STRCMP(T_UE, T_ME) == 0)
|
||||
do_ME = TRUE;
|
||||
else
|
||||
out_str(T_UE);
|
||||
}
|
||||
if (screen_attr & HL_ITALIC) {
|
||||
if (STRCMP(T_CZR, T_ME) == 0)
|
||||
do_ME = TRUE;
|
||||
else
|
||||
out_str(T_CZR);
|
||||
}
|
||||
if (do_ME || (screen_attr & (HL_BOLD | HL_INVERSE)))
|
||||
out_str(T_ME);
|
||||
|
||||
if (t_colors > 1) {
|
||||
/* set Normal cterm colors */
|
||||
if (cterm_normal_fg_color != 0)
|
||||
term_fg_color(cterm_normal_fg_color - 1);
|
||||
if (cterm_normal_bg_color != 0)
|
||||
term_bg_color(cterm_normal_bg_color - 1);
|
||||
if (cterm_normal_fg_bold)
|
||||
out_str(T_MD);
|
||||
}
|
||||
}
|
||||
// Handled in ui.c
|
||||
char buf[20];
|
||||
sprintf(buf, "\033|%dH", screen_attr);
|
||||
OUT_STR(buf);
|
||||
}
|
||||
screen_attr = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset the colors for a cterm. Used when leaving Vim.
|
||||
* The machine specific code may override this again.
|
||||
*/
|
||||
void reset_cterm_colors(void)
|
||||
{
|
||||
if (!abstract_ui && t_colors > 1) {
|
||||
/* set Normal cterm colors */
|
||||
if (cterm_normal_fg_color > 0 || cterm_normal_bg_color > 0) {
|
||||
out_str(T_OP);
|
||||
screen_attr = -1;
|
||||
}
|
||||
if (cterm_normal_fg_bold) {
|
||||
out_str(T_ME);
|
||||
screen_attr = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Put character ScreenLines["off"] on the screen at position "row" and "col",
|
||||
* using the attributes from ScreenAttrs["off"].
|
||||
@ -6138,7 +5859,6 @@ void screen_fill(int start_row, int end_row, int start_col, int end_col, int c1,
|
||||
int end_off;
|
||||
int did_delete;
|
||||
int c;
|
||||
int norm_term;
|
||||
#if defined(FEAT_GUI) || defined(UNIX)
|
||||
int force_next = FALSE;
|
||||
#endif
|
||||
@ -6153,7 +5873,6 @@ void screen_fill(int start_row, int end_row, int start_col, int end_col, int c1,
|
||||
return;
|
||||
|
||||
/* it's a "normal" terminal when not in a GUI or cterm */
|
||||
norm_term = (!abstract_ui && t_colors <= 1);
|
||||
for (row = start_row; row < end_row; ++row) {
|
||||
if (has_mbyte
|
||||
) {
|
||||
@ -6174,11 +5893,7 @@ void screen_fill(int start_row, int end_row, int start_col, int end_col, int c1,
|
||||
did_delete = FALSE;
|
||||
if (c2 == ' '
|
||||
&& end_col == Columns
|
||||
&& can_clear(T_CE)
|
||||
&& (attr == 0
|
||||
|| (norm_term
|
||||
&& attr <= HL_ALL
|
||||
&& ((attr & ~(HL_BOLD | HL_ITALIC)) == 0)))) {
|
||||
&& attr == 0) {
|
||||
/*
|
||||
* check if we really need to clear something
|
||||
*/
|
||||
@ -6227,24 +5942,6 @@ void screen_fill(int start_row, int end_row, int start_col, int end_col, int c1,
|
||||
|| force_next
|
||||
#endif
|
||||
) {
|
||||
#if defined(FEAT_GUI) || defined(UNIX)
|
||||
/* The bold trick may make a single row of pixels appear in
|
||||
* the next character. When a bold character is removed, the
|
||||
* next character should be redrawn too. This happens for our
|
||||
* own GUI and for some xterms. */
|
||||
if (
|
||||
# ifdef UNIX
|
||||
term_is_xterm
|
||||
# endif
|
||||
) {
|
||||
if (ScreenLines[off] != ' '
|
||||
&& (ScreenAttrs[off] > HL_ALL
|
||||
|| ScreenAttrs[off] & HL_BOLD))
|
||||
force_next = TRUE;
|
||||
else
|
||||
force_next = FALSE;
|
||||
}
|
||||
#endif
|
||||
ScreenLines[off] = c;
|
||||
if (enc_utf8) {
|
||||
if (c >= 0x80) {
|
||||
@ -6584,10 +6281,6 @@ static void screenclear2(void)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!abstract_ui) {
|
||||
screen_attr = -1; /* force setting the Normal colors */
|
||||
}
|
||||
|
||||
screen_stop_highlight(); /* don't want highlighting here */
|
||||
|
||||
|
||||
@ -6597,17 +6290,9 @@ static void screenclear2(void)
|
||||
LineWraps[i] = FALSE;
|
||||
}
|
||||
|
||||
if (can_clear(T_CL)) {
|
||||
out_str(T_CL); /* clear the display */
|
||||
clear_cmdline = FALSE;
|
||||
mode_displayed = FALSE;
|
||||
} else {
|
||||
/* can't clear the screen, mark all chars with invalid attributes */
|
||||
for (i = 0; i < Rows; ++i)
|
||||
lineinvalid(LineOffset[i], (int)Columns);
|
||||
clear_cmdline = TRUE;
|
||||
}
|
||||
|
||||
out_str(T_CL); /* clear the display */
|
||||
clear_cmdline = FALSE;
|
||||
mode_displayed = FALSE;
|
||||
screen_cleared = TRUE; /* can use contents of ScreenLines now */
|
||||
|
||||
win_rest_invalid(firstwin);
|
||||
@ -6636,15 +6321,6 @@ static void lineclear(unsigned off, int width)
|
||||
(void)memset(ScreenAttrs + off, 0, (size_t)width * sizeof(sattr_T));
|
||||
}
|
||||
|
||||
/*
|
||||
* Mark one line in ScreenLines invalid by setting the attributes to an
|
||||
* invalid value.
|
||||
*/
|
||||
static void lineinvalid(unsigned off, int width)
|
||||
{
|
||||
(void)memset(ScreenAttrs + off, -1, (size_t)width * sizeof(sattr_T));
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy part of a Screenline for vertically split window "wp".
|
||||
*/
|
||||
@ -6671,16 +6347,6 @@ static void linecopy(int to, int from, win_T *wp)
|
||||
wp->w_width * sizeof(sattr_T));
|
||||
}
|
||||
|
||||
/*
|
||||
* Return TRUE if clearing with term string "p" would work.
|
||||
* It can't work when the string is empty or it won't set the right background.
|
||||
*/
|
||||
int can_clear(char_u *p)
|
||||
{
|
||||
return abstract_ui || (*p != NUL && (t_colors <= 1
|
||||
|| cterm_normal_bg_color == 0 || *T_UT != NUL));
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset cursor position. Use whenever cursor was moved because of outputting
|
||||
* something directly to the screen (shell commands) or a terminal control
|
||||
@ -7167,7 +6833,7 @@ screen_ins_lines (
|
||||
int cursor_row;
|
||||
int type;
|
||||
int result_empty;
|
||||
int can_ce = can_clear(T_CE);
|
||||
int can_ce = true;
|
||||
|
||||
/*
|
||||
* FAIL if
|
||||
@ -7207,7 +6873,7 @@ screen_ins_lines (
|
||||
result_empty = (row + line_count >= end);
|
||||
if (wp != NULL && wp->w_width != Columns && *T_CSV == NUL)
|
||||
type = USE_REDRAW;
|
||||
else if (can_clear(T_CD) && result_empty)
|
||||
else if (result_empty)
|
||||
type = USE_T_CD;
|
||||
else if (*T_CAL != NUL && (line_count > 1 || *T_AL == NUL))
|
||||
type = USE_T_CAL;
|
||||
@ -7260,10 +6926,7 @@ screen_ins_lines (
|
||||
while ((j -= line_count) >= row)
|
||||
linecopy(j + line_count, j, wp);
|
||||
j += line_count;
|
||||
if (can_clear((char_u *)" "))
|
||||
lineclear(LineOffset[j] + wp->w_wincol, wp->w_width);
|
||||
else
|
||||
lineinvalid(LineOffset[j] + wp->w_wincol, wp->w_width);
|
||||
lineclear(LineOffset[j] + wp->w_wincol, wp->w_width);
|
||||
LineWraps[j] = FALSE;
|
||||
} else {
|
||||
j = end - 1 - i;
|
||||
@ -7274,10 +6937,7 @@ screen_ins_lines (
|
||||
}
|
||||
LineOffset[j + line_count] = temp;
|
||||
LineWraps[j + line_count] = FALSE;
|
||||
if (can_clear((char_u *)" "))
|
||||
lineclear(temp, (int)Columns);
|
||||
else
|
||||
lineinvalid(temp, (int)Columns);
|
||||
lineclear(temp, (int)Columns);
|
||||
}
|
||||
}
|
||||
|
||||
@ -7364,7 +7024,7 @@ screen_del_lines (
|
||||
* We can delete lines only when 'db' flag not set or when 'ce' option
|
||||
* available.
|
||||
*/
|
||||
can_delete = (*T_DB == NUL || can_clear(T_CE));
|
||||
can_delete = true;
|
||||
|
||||
/*
|
||||
* There are six ways to delete lines:
|
||||
@ -7380,7 +7040,7 @@ screen_del_lines (
|
||||
*/
|
||||
if (wp != NULL && wp->w_width != Columns && *T_CSV == NUL)
|
||||
type = USE_REDRAW;
|
||||
else if (can_clear(T_CD) && result_empty)
|
||||
else if (result_empty)
|
||||
type = USE_T_CD;
|
||||
else if (row == 0 && (
|
||||
/* On the Amiga, somehow '\n' on the last line doesn't always scroll
|
||||
@ -7390,9 +7050,7 @@ screen_del_lines (
|
||||
type = USE_NL;
|
||||
else if (*T_CDL != NUL && line_count > 1 && can_delete)
|
||||
type = USE_T_CDL;
|
||||
else if (can_clear(T_CE) && result_empty
|
||||
&& (wp == NULL || wp->w_width == Columns)
|
||||
)
|
||||
else if (result_empty && (wp == NULL || wp->w_width == Columns))
|
||||
type = USE_T_CE;
|
||||
else if (*T_DL != NUL && can_delete)
|
||||
type = USE_T_DL;
|
||||
@ -7424,10 +7082,7 @@ screen_del_lines (
|
||||
while ((j += line_count) <= end - 1)
|
||||
linecopy(j - line_count, j, wp);
|
||||
j -= line_count;
|
||||
if (can_clear((char_u *)" "))
|
||||
lineclear(LineOffset[j] + wp->w_wincol, wp->w_width);
|
||||
else
|
||||
lineinvalid(LineOffset[j] + wp->w_wincol, wp->w_width);
|
||||
lineclear(LineOffset[j] + wp->w_wincol, wp->w_width);
|
||||
LineWraps[j] = FALSE;
|
||||
} else {
|
||||
/* whole width, moving the line pointers is faster */
|
||||
@ -7439,10 +7094,7 @@ screen_del_lines (
|
||||
}
|
||||
LineOffset[j - line_count] = temp;
|
||||
LineWraps[j - line_count] = FALSE;
|
||||
if (can_clear((char_u *)" "))
|
||||
lineclear(temp, (int)Columns);
|
||||
else
|
||||
lineinvalid(temp, (int)Columns);
|
||||
lineclear(temp, (int)Columns);
|
||||
}
|
||||
}
|
||||
|
||||
@ -8153,7 +7805,7 @@ int screen_screenrow(void)
|
||||
* If 'mustset' is FALSE, we may try to get the real window size and if
|
||||
* it fails use 'width' and 'height'.
|
||||
*/
|
||||
void screen_resize(int width, int height, int mustset)
|
||||
void screen_resize(int width, int height)
|
||||
{
|
||||
static int busy = FALSE;
|
||||
|
||||
@ -8182,24 +7834,15 @@ void screen_resize(int width, int height, int mustset)
|
||||
|
||||
++busy;
|
||||
|
||||
// TODO(tarruda): "mustset" is still used in the old tests, which don't use
|
||||
// "abstract_ui" yet. This will change when a new TUI is merged.
|
||||
if (abstract_ui || mustset || (ui_get_shellsize() == FAIL && height != 0)) {
|
||||
Rows = height;
|
||||
Columns = width;
|
||||
}
|
||||
Rows = height;
|
||||
Columns = width;
|
||||
check_shellsize();
|
||||
height = Rows;
|
||||
width = Columns;
|
||||
|
||||
if (abstract_ui) {
|
||||
// Clear the output buffer to ensure UIs don't receive redraw command meant
|
||||
// for invalid screen sizes.
|
||||
out_buf_clear();
|
||||
ui_resize(width, height);
|
||||
} else {
|
||||
mch_set_shellsize();
|
||||
}
|
||||
// Clear the output buffer to ensure UIs don't receive redraw command meant
|
||||
// for invalid screen sizes.
|
||||
out_buf_clear();
|
||||
ui_resize(width, height);
|
||||
|
||||
/* The window layout used to be adjusted here, but it now happens in
|
||||
* screenalloc() (also invoked from screenclear()). That is because the
|
||||
|
@ -351,40 +351,3 @@ bool sha256_self_test(void)
|
||||
}
|
||||
return failures == false;
|
||||
}
|
||||
|
||||
/// Fill "header[header_len]" with random_data.
|
||||
/// Also "salt[salt_len]" when "salt" is not NULL.
|
||||
///
|
||||
/// @param header
|
||||
/// @param header_len
|
||||
/// @param salt
|
||||
/// @param salt_len
|
||||
void sha2_seed(char_u *restrict header, size_t header_len,
|
||||
char_u *restrict salt, size_t salt_len)
|
||||
{
|
||||
static char_u random_data[1000];
|
||||
char_u sha256sum[SHA256_SUM_SIZE];
|
||||
context_sha256_T ctx;
|
||||
|
||||
unsigned int seed = (unsigned int) os_hrtime();
|
||||
|
||||
size_t i;
|
||||
for (i = 0; i < sizeof(random_data) - 1; i++) {
|
||||
random_data[i] = (char_u) ((os_hrtime() ^ (uint64_t)rand_r(&seed)) & 0xff);
|
||||
}
|
||||
sha256_start(&ctx);
|
||||
sha256_update(&ctx, random_data, sizeof(random_data));
|
||||
sha256_finish(&ctx, sha256sum);
|
||||
|
||||
// put first block into header.
|
||||
for (i = 0; i < header_len; i++) {
|
||||
header[i] = sha256sum[i % sizeof(sha256sum)];
|
||||
}
|
||||
|
||||
// put remaining block into salt.
|
||||
if (salt != NULL) {
|
||||
for (i = 0; i < salt_len; i++) {
|
||||
salt[i] = sha256sum[(i + header_len) % sizeof(sha256sum)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -300,17 +300,6 @@ void del_trailing_spaces(char_u *ptr)
|
||||
*q = NUL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Like strncpy(), but always terminate the result with one NUL.
|
||||
* "to" must be "len + 1" long!
|
||||
*/
|
||||
void vim_strncpy(char_u *restrict to, const char_u *restrict from, size_t len)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
STRNCPY(to, from, len);
|
||||
to[len] = NUL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Like strcat(), but make sure the result fits in "tosize" bytes and is
|
||||
* always NUL terminated.
|
||||
|
@ -49,40 +49,32 @@
|
||||
#include "nvim/os/os.h"
|
||||
#include "nvim/os/time.h"
|
||||
|
||||
/*
|
||||
* Structure that stores information about a highlight group.
|
||||
* The ID of a highlight group is also called group ID. It is the index in
|
||||
* the highlight_ga array PLUS ONE.
|
||||
*/
|
||||
// Structure that stores information about a highlight group.
|
||||
// The ID of a highlight group is also called group ID. It is the index in
|
||||
// the highlight_ga array PLUS ONE.
|
||||
struct hl_group {
|
||||
char_u *sg_name; /* highlight group name */
|
||||
char_u *sg_name_u; /* uppercase of sg_name */
|
||||
/* for normal terminals */
|
||||
int sg_term; /* "term=" highlighting attributes */
|
||||
char_u *sg_start; /* terminal string for start highl */
|
||||
char_u *sg_stop; /* terminal string for stop highl */
|
||||
int sg_term_attr; /* Screen attr for term mode */
|
||||
/* for color terminals */
|
||||
int sg_cterm; /* "cterm=" highlighting attr */
|
||||
int sg_cterm_bold; /* bold attr was set for light color */
|
||||
int sg_cterm_fg; /* terminal fg color number + 1 */
|
||||
int sg_cterm_bg; /* terminal bg color number + 1 */
|
||||
int sg_cterm_attr; /* Screen attr for color term mode */
|
||||
/* Store the sp color name for the GUI or synIDattr() */
|
||||
int sg_gui; /* "gui=" highlighting attributes */
|
||||
char_u *sg_name; // highlight group name
|
||||
char_u *sg_name_u; // uppercase of sg_name
|
||||
int sg_attr; // Screen attr
|
||||
int sg_link; // link to this highlight group ID
|
||||
int sg_set; // combination of SG_* flags
|
||||
scid_T sg_scriptID; // script in which the group was last set
|
||||
// for terminal UIs
|
||||
int sg_cterm; // "cterm=" highlighting attr
|
||||
int sg_cterm_fg; // terminal fg color number + 1
|
||||
int sg_cterm_bg; // terminal bg color number + 1
|
||||
int sg_cterm_bold; // bold attr was set for light color
|
||||
// for RGB UIs
|
||||
int sg_gui; // "gui=" highlighting attributes
|
||||
RgbValue sg_rgb_fg; // RGB foreground color
|
||||
RgbValue sg_rgb_bg; // RGB background color
|
||||
uint8_t *sg_rgb_fg_name; // RGB foreground color name
|
||||
uint8_t *sg_rgb_bg_name; // RGB background color name
|
||||
int sg_link; /* link to this highlight group ID */
|
||||
int sg_set; /* combination of SG_* flags */
|
||||
scid_T sg_scriptID; /* script in which the group was last set */
|
||||
};
|
||||
|
||||
#define SG_TERM 1 /* term has been set */
|
||||
#define SG_CTERM 2 /* cterm has been set */
|
||||
#define SG_GUI 4 /* gui has been set */
|
||||
#define SG_LINK 8 /* link has been set */
|
||||
#define SG_CTERM 2 // cterm has been set
|
||||
#define SG_GUI 4 // gui has been set
|
||||
#define SG_LINK 8 // link has been set
|
||||
|
||||
// highlight groups for 'highlight' option
|
||||
static garray_T highlight_ga = GA_EMPTY_INIT_VALUE;
|
||||
@ -221,7 +213,7 @@ struct name_list {
|
||||
/*
|
||||
* An attribute number is the index in attr_table plus ATTR_OFF.
|
||||
*/
|
||||
#define ATTR_OFF (HL_ALL + 1)
|
||||
#define ATTR_OFF 1
|
||||
|
||||
|
||||
static char *(spo_name_tab[SPO_COUNT]) =
|
||||
@ -6054,7 +6046,6 @@ do_highlight (
|
||||
)
|
||||
{
|
||||
char_u *name_end;
|
||||
char_u *p;
|
||||
char_u *linep;
|
||||
char_u *key_start;
|
||||
char_u *arg_start;
|
||||
@ -6242,7 +6233,7 @@ do_highlight (
|
||||
if (STRCMP(key, "NONE") == 0) {
|
||||
if (!init || HL_TABLE()[idx].sg_set == 0) {
|
||||
if (!init)
|
||||
HL_TABLE()[idx].sg_set |= SG_TERM+SG_CTERM+SG_GUI;
|
||||
HL_TABLE()[idx].sg_set |= SG_CTERM+SG_GUI;
|
||||
highlight_clear(idx);
|
||||
}
|
||||
continue;
|
||||
@ -6312,20 +6303,14 @@ do_highlight (
|
||||
}
|
||||
if (error)
|
||||
break;
|
||||
if (*key == 'T') {
|
||||
if (!init || !(HL_TABLE()[idx].sg_set & SG_TERM)) {
|
||||
if (!init)
|
||||
HL_TABLE()[idx].sg_set |= SG_TERM;
|
||||
HL_TABLE()[idx].sg_term = attr;
|
||||
}
|
||||
} else if (*key == 'C') {
|
||||
if (*key == 'C') {
|
||||
if (!init || !(HL_TABLE()[idx].sg_set & SG_CTERM)) {
|
||||
if (!init)
|
||||
HL_TABLE()[idx].sg_set |= SG_CTERM;
|
||||
HL_TABLE()[idx].sg_cterm = attr;
|
||||
HL_TABLE()[idx].sg_cterm_bold = FALSE;
|
||||
}
|
||||
} else {
|
||||
} else if (*key == 'G') {
|
||||
if (!init || !(HL_TABLE()[idx].sg_set & SG_GUI)) {
|
||||
if (!init)
|
||||
HL_TABLE()[idx].sg_set |= SG_GUI;
|
||||
@ -6438,27 +6423,17 @@ do_highlight (
|
||||
}
|
||||
color &= 7; /* truncate to 8 colors */
|
||||
} else if (t_colors == 16 || t_colors == 88 || t_colors == 256) {
|
||||
/*
|
||||
* Guess: if the termcap entry ends in 'm', it is
|
||||
* probably an xterm-like terminal. Use the changed
|
||||
* order for colors.
|
||||
*/
|
||||
if (*T_CAF != NUL)
|
||||
p = T_CAF;
|
||||
else
|
||||
p = T_CSF;
|
||||
if (abstract_ui || (*p != NUL && *(p + STRLEN(p) - 1) == 'm'))
|
||||
switch (t_colors) {
|
||||
case 16:
|
||||
color = color_numbers_8[i];
|
||||
break;
|
||||
case 88:
|
||||
color = color_numbers_88[i];
|
||||
break;
|
||||
case 256:
|
||||
color = color_numbers_256[i];
|
||||
break;
|
||||
}
|
||||
switch (t_colors) {
|
||||
case 16:
|
||||
color = color_numbers_8[i];
|
||||
break;
|
||||
case 88:
|
||||
color = color_numbers_88[i];
|
||||
break;
|
||||
case 256:
|
||||
color = color_numbers_256[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -6471,8 +6446,6 @@ do_highlight (
|
||||
cterm_normal_fg_bold = (HL_TABLE()[idx].sg_cterm & HL_BOLD);
|
||||
{
|
||||
must_redraw = CLEAR;
|
||||
if (termcap_active && color >= 0)
|
||||
term_fg_color(color);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -6482,8 +6455,6 @@ do_highlight (
|
||||
{
|
||||
must_redraw = CLEAR;
|
||||
if (color >= 0) {
|
||||
if (termcap_active)
|
||||
term_bg_color(color);
|
||||
if (t_colors < 16)
|
||||
i = (color == 0 || color == 4);
|
||||
else
|
||||
@ -6536,73 +6507,9 @@ do_highlight (
|
||||
normal_bg = HL_TABLE()[idx].sg_rgb_bg;
|
||||
}
|
||||
} else if (STRCMP(key, "GUISP") == 0) {
|
||||
// Ignored
|
||||
// Ignored for now
|
||||
} else if (STRCMP(key, "START") == 0 || STRCMP(key, "STOP") == 0) {
|
||||
char_u buf[100];
|
||||
char_u *tname;
|
||||
|
||||
if (!init)
|
||||
HL_TABLE()[idx].sg_set |= SG_TERM;
|
||||
|
||||
/*
|
||||
* The "start" and "stop" arguments can be a literal escape
|
||||
* sequence, or a comma separated list of terminal codes.
|
||||
*/
|
||||
if (STRNCMP(arg, "t_", 2) == 0) {
|
||||
off = 0;
|
||||
buf[0] = 0;
|
||||
while (arg[off] != NUL) {
|
||||
/* Isolate one termcap name */
|
||||
for (len = 0; arg[off + len] &&
|
||||
arg[off + len] != ','; ++len)
|
||||
;
|
||||
tname = vim_strnsave(arg + off, len);
|
||||
/* lookup the escape sequence for the item */
|
||||
p = get_term_code(tname);
|
||||
free(tname);
|
||||
if (p == NULL) /* ignore non-existing things */
|
||||
p = (char_u *)"";
|
||||
|
||||
/* Append it to the already found stuff */
|
||||
if ((int)(STRLEN(buf) + STRLEN(p)) >= 99) {
|
||||
EMSG2(_("E422: terminal code too long: %s"), arg);
|
||||
error = TRUE;
|
||||
break;
|
||||
}
|
||||
STRCAT(buf, p);
|
||||
|
||||
/* Advance to the next item */
|
||||
off += len;
|
||||
if (arg[off] == ',') /* another one follows */
|
||||
++off;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Copy characters from arg[] to buf[], translating <> codes.
|
||||
*/
|
||||
for (p = arg, off = 0; off < 100 - 6 && *p; ) {
|
||||
len = (int)trans_special(&p, buf + off, FALSE);
|
||||
if (len > 0) /* recognized special char */
|
||||
off += len;
|
||||
else /* copy as normal char */
|
||||
buf[off++] = *p++;
|
||||
}
|
||||
buf[off] = NUL;
|
||||
}
|
||||
if (error)
|
||||
break;
|
||||
|
||||
if (STRCMP(buf, "NONE") == 0) /* resetting the value */
|
||||
p = NULL;
|
||||
else
|
||||
p = vim_strsave(buf);
|
||||
if (key[2] == 'A') {
|
||||
free(HL_TABLE()[idx].sg_start);
|
||||
HL_TABLE()[idx].sg_start = p;
|
||||
} else {
|
||||
free(HL_TABLE()[idx].sg_stop);
|
||||
HL_TABLE()[idx].sg_stop = p;
|
||||
}
|
||||
// Ignored for now
|
||||
} else {
|
||||
EMSG2(_("E423: Illegal argument: %s"), key_start);
|
||||
error = TRUE;
|
||||
@ -6628,12 +6535,9 @@ do_highlight (
|
||||
syn_unadd_group();
|
||||
else {
|
||||
if (is_normal_group) {
|
||||
HL_TABLE()[idx].sg_term_attr = 0;
|
||||
HL_TABLE()[idx].sg_cterm_attr = 0;
|
||||
if (abstract_ui) {
|
||||
// If the normal group has changed, it is simpler to refresh every UI
|
||||
ui_refresh();
|
||||
}
|
||||
HL_TABLE()[idx].sg_attr = 0;
|
||||
// If the normal group has changed, it is simpler to refresh every UI
|
||||
ui_refresh();
|
||||
} else
|
||||
set_hl_attr(idx);
|
||||
HL_TABLE()[idx].sg_scriptID = current_SID;
|
||||
@ -6678,10 +6582,11 @@ void restore_cterm_colors(void)
|
||||
*/
|
||||
static int hl_has_settings(int idx, int check_link)
|
||||
{
|
||||
return HL_TABLE()[idx].sg_term_attr != 0
|
||||
|| HL_TABLE()[idx].sg_cterm_attr != 0
|
||||
return HL_TABLE()[idx].sg_attr != 0
|
||||
|| HL_TABLE()[idx].sg_cterm_fg != 0
|
||||
|| HL_TABLE()[idx].sg_cterm_bg != 0
|
||||
|| HL_TABLE()[idx].sg_rgb_fg_name != NULL
|
||||
|| HL_TABLE()[idx].sg_rgb_bg_name != NULL
|
||||
|| (check_link && (HL_TABLE()[idx].sg_set & SG_LINK));
|
||||
}
|
||||
|
||||
@ -6690,17 +6595,11 @@ static int hl_has_settings(int idx, int check_link)
|
||||
*/
|
||||
static void highlight_clear(int idx)
|
||||
{
|
||||
HL_TABLE()[idx].sg_term = 0;
|
||||
free(HL_TABLE()[idx].sg_start);
|
||||
HL_TABLE()[idx].sg_start = NULL;
|
||||
free(HL_TABLE()[idx].sg_stop);
|
||||
HL_TABLE()[idx].sg_stop = NULL;
|
||||
HL_TABLE()[idx].sg_term_attr = 0;
|
||||
HL_TABLE()[idx].sg_attr = 0;
|
||||
HL_TABLE()[idx].sg_cterm = 0;
|
||||
HL_TABLE()[idx].sg_cterm_bold = FALSE;
|
||||
HL_TABLE()[idx].sg_cterm_fg = 0;
|
||||
HL_TABLE()[idx].sg_cterm_bg = 0;
|
||||
HL_TABLE()[idx].sg_cterm_attr = 0;
|
||||
HL_TABLE()[idx].sg_gui = 0;
|
||||
HL_TABLE()[idx].sg_rgb_fg = -1;
|
||||
HL_TABLE()[idx].sg_rgb_bg = -1;
|
||||
@ -6720,23 +6619,20 @@ static void highlight_clear(int idx)
|
||||
* Note that this table is used by ALL buffers. This is required because the
|
||||
* GUI can redraw at any time for any buffer.
|
||||
*/
|
||||
static garray_T term_attr_table = GA_EMPTY_INIT_VALUE;
|
||||
static garray_T attr_table = GA_EMPTY_INIT_VALUE;
|
||||
|
||||
#define TERM_ATTR_ENTRY(idx) ((attrentry_T *)term_attr_table.ga_data)[idx]
|
||||
|
||||
static garray_T cterm_attr_table = GA_EMPTY_INIT_VALUE;
|
||||
|
||||
#define CTERM_ATTR_ENTRY(idx) ((attrentry_T *)cterm_attr_table.ga_data)[idx]
|
||||
#define ATTR_ENTRY(idx) ((attrentry_T *)attr_table.ga_data)[idx]
|
||||
|
||||
|
||||
/*
|
||||
* Return the attr number for a set of colors and font.
|
||||
* Add a new entry to the term_attr_table, cterm_attr_table or gui_attr_table
|
||||
* Add a new entry to the term_attr_table, attr_table or gui_attr_table
|
||||
* if the combination is new.
|
||||
* Return 0 for error.
|
||||
*/
|
||||
static int get_attr_entry(garray_T *table, attrentry_T *aep)
|
||||
static int get_attr_entry(attrentry_T *aep)
|
||||
{
|
||||
garray_T *table = &attr_table;
|
||||
attrentry_T *taep;
|
||||
static int recursive = FALSE;
|
||||
|
||||
@ -6751,31 +6647,14 @@ static int get_attr_entry(garray_T *table, attrentry_T *aep)
|
||||
*/
|
||||
for (int i = 0; i < table->ga_len; ++i) {
|
||||
taep = &(((attrentry_T *)table->ga_data)[i]);
|
||||
if ( aep->ae_attr == taep->ae_attr
|
||||
&& (
|
||||
(table == &term_attr_table
|
||||
&& (aep->ae_u.term.start == NULL)
|
||||
== (taep->ae_u.term.start == NULL)
|
||||
&& (aep->ae_u.term.start == NULL
|
||||
|| STRCMP(aep->ae_u.term.start,
|
||||
taep->ae_u.term.start) == 0)
|
||||
&& (aep->ae_u.term.stop == NULL)
|
||||
== (taep->ae_u.term.stop == NULL)
|
||||
&& (aep->ae_u.term.stop == NULL
|
||||
|| STRCMP(aep->ae_u.term.stop,
|
||||
taep->ae_u.term.stop) == 0))
|
||||
|| (table == &cterm_attr_table
|
||||
&& aep->ae_u.cterm.fg_color
|
||||
== taep->ae_u.cterm.fg_color
|
||||
&& aep->ae_u.cterm.bg_color
|
||||
== taep->ae_u.cterm.bg_color
|
||||
&& aep->fg_color
|
||||
== taep->fg_color
|
||||
&& aep->bg_color
|
||||
== taep->bg_color)
|
||||
))
|
||||
|
||||
if (aep->cterm_ae_attr == taep->cterm_ae_attr
|
||||
&& aep->cterm_fg_color == taep->cterm_fg_color
|
||||
&& aep->cterm_bg_color == taep->cterm_bg_color
|
||||
&& aep->rgb_ae_attr == taep->rgb_ae_attr
|
||||
&& aep->rgb_fg_color == taep->rgb_fg_color
|
||||
&& aep->rgb_bg_color == taep->rgb_bg_color) {
|
||||
return i + ATTR_OFF;
|
||||
}
|
||||
}
|
||||
|
||||
if (table->ga_len + ATTR_OFF > MAX_TYPENR) {
|
||||
@ -6801,156 +6680,83 @@ static int get_attr_entry(garray_T *table, attrentry_T *aep)
|
||||
recursive = FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is a new combination of colors and font, add an entry.
|
||||
*/
|
||||
|
||||
// This is a new combination of colors and font, add an entry.
|
||||
taep = GA_APPEND_VIA_PTR(attrentry_T, table);
|
||||
memset(taep, 0, sizeof(*taep));
|
||||
taep->ae_attr = aep->ae_attr;
|
||||
if (table == &term_attr_table) {
|
||||
if (aep->ae_u.term.start == NULL)
|
||||
taep->ae_u.term.start = NULL;
|
||||
else
|
||||
taep->ae_u.term.start = vim_strsave(aep->ae_u.term.start);
|
||||
if (aep->ae_u.term.stop == NULL)
|
||||
taep->ae_u.term.stop = NULL;
|
||||
else
|
||||
taep->ae_u.term.stop = vim_strsave(aep->ae_u.term.stop);
|
||||
} else if (table == &cterm_attr_table) {
|
||||
taep->ae_u.cterm.fg_color = aep->ae_u.cterm.fg_color;
|
||||
taep->ae_u.cterm.bg_color = aep->ae_u.cterm.bg_color;
|
||||
taep->fg_color = aep->fg_color;
|
||||
taep->bg_color = aep->bg_color;
|
||||
}
|
||||
taep->cterm_ae_attr = aep->cterm_ae_attr;
|
||||
taep->cterm_fg_color = aep->cterm_fg_color;
|
||||
taep->cterm_bg_color = aep->cterm_bg_color;
|
||||
taep->rgb_ae_attr = aep->rgb_ae_attr;
|
||||
taep->rgb_fg_color = aep->rgb_fg_color;
|
||||
taep->rgb_bg_color = aep->rgb_bg_color;
|
||||
|
||||
return table->ga_len - 1 + ATTR_OFF;
|
||||
}
|
||||
|
||||
/*
|
||||
* Clear all highlight tables.
|
||||
*/
|
||||
// Clear all highlight tables.
|
||||
void clear_hl_tables(void)
|
||||
{
|
||||
attrentry_T *taep;
|
||||
|
||||
for (int i = 0; i < term_attr_table.ga_len; ++i) {
|
||||
taep = &(((attrentry_T *)term_attr_table.ga_data)[i]);
|
||||
free(taep->ae_u.term.start);
|
||||
free(taep->ae_u.term.stop);
|
||||
}
|
||||
ga_clear(&term_attr_table);
|
||||
ga_clear(&cterm_attr_table);
|
||||
ga_clear(&attr_table);
|
||||
}
|
||||
|
||||
/*
|
||||
* Combine special attributes (e.g., for spelling) with other attributes
|
||||
* (e.g., for syntax highlighting).
|
||||
* "prim_attr" overrules "char_attr".
|
||||
* This creates a new group when required.
|
||||
* Since we expect there to be few spelling mistakes we don't cache the
|
||||
* result.
|
||||
* Return the resulting attributes.
|
||||
*/
|
||||
// Combine special attributes (e.g., for spelling) with other attributes
|
||||
// (e.g., for syntax highlighting).
|
||||
// "prim_attr" overrules "char_attr".
|
||||
// This creates a new group when required.
|
||||
// Since we expect there to be few spelling mistakes we don't cache the
|
||||
// result.
|
||||
// Return the resulting attributes.
|
||||
int hl_combine_attr(int char_attr, int prim_attr)
|
||||
{
|
||||
attrentry_T *char_aep = NULL;
|
||||
attrentry_T *spell_aep;
|
||||
attrentry_T new_en;
|
||||
|
||||
if (char_attr == 0)
|
||||
if (char_attr == 0) {
|
||||
return prim_attr;
|
||||
if (char_attr <= HL_ALL && prim_attr <= HL_ALL)
|
||||
return char_attr | prim_attr;
|
||||
|
||||
if (abstract_ui || t_colors > 1) {
|
||||
if (char_attr > HL_ALL)
|
||||
char_aep = syn_cterm_attr2entry(char_attr);
|
||||
if (char_aep != NULL)
|
||||
new_en = *char_aep;
|
||||
else {
|
||||
memset(&new_en, 0, sizeof(new_en));
|
||||
if (char_attr <= HL_ALL)
|
||||
new_en.ae_attr = char_attr;
|
||||
}
|
||||
|
||||
if (prim_attr <= HL_ALL)
|
||||
new_en.ae_attr |= prim_attr;
|
||||
else {
|
||||
spell_aep = syn_cterm_attr2entry(prim_attr);
|
||||
if (spell_aep != NULL) {
|
||||
new_en.ae_attr |= spell_aep->ae_attr;
|
||||
if (spell_aep->ae_u.cterm.fg_color > 0)
|
||||
new_en.ae_u.cterm.fg_color = spell_aep->ae_u.cterm.fg_color;
|
||||
if (spell_aep->ae_u.cterm.bg_color > 0)
|
||||
new_en.ae_u.cterm.bg_color = spell_aep->ae_u.cterm.bg_color;
|
||||
if (spell_aep->fg_color >= 0)
|
||||
new_en.fg_color = spell_aep->fg_color;
|
||||
if (spell_aep->bg_color >= 0)
|
||||
new_en.bg_color = spell_aep->bg_color;
|
||||
}
|
||||
}
|
||||
return get_attr_entry(&cterm_attr_table, &new_en);
|
||||
}
|
||||
|
||||
if (char_attr > HL_ALL)
|
||||
char_aep = syn_term_attr2entry(char_attr);
|
||||
if (char_aep != NULL)
|
||||
// Find the entry for char_attr
|
||||
char_aep = syn_cterm_attr2entry(char_attr);
|
||||
|
||||
if (char_aep != NULL) {
|
||||
// Copy all attributes from char_aep to the new entry
|
||||
new_en = *char_aep;
|
||||
else {
|
||||
} else {
|
||||
memset(&new_en, 0, sizeof(new_en));
|
||||
if (char_attr <= HL_ALL)
|
||||
new_en.ae_attr = char_attr;
|
||||
}
|
||||
|
||||
if (prim_attr <= HL_ALL)
|
||||
new_en.ae_attr |= prim_attr;
|
||||
else {
|
||||
spell_aep = syn_term_attr2entry(prim_attr);
|
||||
if (spell_aep != NULL) {
|
||||
new_en.ae_attr |= spell_aep->ae_attr;
|
||||
if (spell_aep->ae_u.term.start != NULL) {
|
||||
new_en.ae_u.term.start = spell_aep->ae_u.term.start;
|
||||
new_en.ae_u.term.stop = spell_aep->ae_u.term.stop;
|
||||
}
|
||||
spell_aep = syn_cterm_attr2entry(prim_attr);
|
||||
if (spell_aep != NULL) {
|
||||
new_en.cterm_ae_attr |= spell_aep->cterm_ae_attr;
|
||||
new_en.rgb_ae_attr |= spell_aep->rgb_ae_attr;
|
||||
|
||||
if (spell_aep->cterm_fg_color > 0) {
|
||||
new_en.cterm_fg_color = spell_aep->cterm_fg_color;
|
||||
}
|
||||
|
||||
if (spell_aep->cterm_bg_color > 0) {
|
||||
new_en.cterm_bg_color = spell_aep->cterm_bg_color;
|
||||
}
|
||||
|
||||
if (spell_aep->rgb_fg_color >= 0) {
|
||||
new_en.rgb_fg_color = spell_aep->rgb_fg_color;
|
||||
}
|
||||
|
||||
if (spell_aep->rgb_bg_color >= 0) {
|
||||
new_en.rgb_bg_color = spell_aep->rgb_bg_color;
|
||||
}
|
||||
}
|
||||
return get_attr_entry(&term_attr_table, &new_en);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Get the highlight attributes (HL_BOLD etc.) from an attribute nr.
|
||||
* Only to be used when "attr" > HL_ALL.
|
||||
*/
|
||||
int syn_attr2attr(int attr)
|
||||
{
|
||||
attrentry_T *aep;
|
||||
|
||||
if (abstract_ui || t_colors > 1)
|
||||
aep = syn_cterm_attr2entry(attr);
|
||||
else
|
||||
aep = syn_term_attr2entry(attr);
|
||||
|
||||
if (aep == NULL) /* highlighting not set */
|
||||
return 0;
|
||||
return aep->ae_attr;
|
||||
}
|
||||
|
||||
|
||||
attrentry_T *syn_term_attr2entry(int attr)
|
||||
{
|
||||
attr -= ATTR_OFF;
|
||||
if (attr >= term_attr_table.ga_len) /* did ":syntax clear" */
|
||||
return NULL;
|
||||
return &(TERM_ATTR_ENTRY(attr));
|
||||
return get_attr_entry(&new_en);
|
||||
}
|
||||
|
||||
attrentry_T *syn_cterm_attr2entry(int attr)
|
||||
{
|
||||
attr -= ATTR_OFF;
|
||||
if (attr >= cterm_attr_table.ga_len) /* did ":syntax clear" */
|
||||
if (attr >= attr_table.ga_len) /* did ":syntax clear" */
|
||||
return NULL;
|
||||
return &(CTERM_ATTR_ENTRY(attr));
|
||||
return &(ATTR_ENTRY(attr));
|
||||
}
|
||||
|
||||
#define LIST_ATTR 1
|
||||
@ -6964,13 +6770,6 @@ static void highlight_list_one(int id)
|
||||
|
||||
sgp = &HL_TABLE()[id - 1]; /* index is ID minus one */
|
||||
|
||||
didh = highlight_list_arg(id, didh, LIST_ATTR,
|
||||
sgp->sg_term, NULL, "term");
|
||||
didh = highlight_list_arg(id, didh, LIST_STRING,
|
||||
0, sgp->sg_start, "start");
|
||||
didh = highlight_list_arg(id, didh, LIST_STRING,
|
||||
0, sgp->sg_stop, "stop");
|
||||
|
||||
didh = highlight_list_arg(id, didh, LIST_ATTR,
|
||||
sgp->sg_cterm, NULL, "cterm");
|
||||
didh = highlight_list_arg(id, didh, LIST_INT,
|
||||
@ -7049,7 +6848,7 @@ char_u *
|
||||
highlight_has_attr (
|
||||
int id,
|
||||
int flag,
|
||||
int modec /* 'g' for GUI, 'c' for cterm, 't' for term */
|
||||
int modec // 'g' for GUI, 'c' for cterm
|
||||
)
|
||||
{
|
||||
int attr;
|
||||
@ -7057,12 +6856,11 @@ highlight_has_attr (
|
||||
if (id <= 0 || id > highlight_ga.ga_len)
|
||||
return NULL;
|
||||
|
||||
if (modec == 'g')
|
||||
if (modec == 'g') {
|
||||
attr = HL_TABLE()[id - 1].sg_gui;
|
||||
else if (modec == 'c')
|
||||
} else {
|
||||
attr = HL_TABLE()[id - 1].sg_cterm;
|
||||
else
|
||||
attr = HL_TABLE()[id - 1].sg_term;
|
||||
}
|
||||
|
||||
if (attr & flag)
|
||||
return (char_u *)"1";
|
||||
@ -7179,37 +6977,16 @@ set_hl_attr (
|
||||
if (sgp->sg_name_u != NULL && STRCMP(sgp->sg_name_u, "NORMAL") == 0)
|
||||
return;
|
||||
|
||||
/*
|
||||
* For the term mode: If there are other than "normal" highlighting
|
||||
* attributes, need to allocate an attr number.
|
||||
*/
|
||||
if (sgp->sg_start == NULL && sgp->sg_stop == NULL)
|
||||
sgp->sg_term_attr = sgp->sg_term;
|
||||
else {
|
||||
at_en.ae_attr = sgp->sg_term;
|
||||
at_en.ae_u.term.start = sgp->sg_start;
|
||||
at_en.ae_u.term.stop = sgp->sg_stop;
|
||||
sgp->sg_term_attr = get_attr_entry(&term_attr_table, &at_en);
|
||||
}
|
||||
|
||||
/*
|
||||
* For the color term mode: If there are other than "normal"
|
||||
* highlighting attributes, need to allocate an attr number.
|
||||
*/
|
||||
if (sgp->sg_cterm_fg == 0 && sgp->sg_cterm_bg == 0
|
||||
&& sgp->sg_rgb_fg == -1 && sgp->sg_rgb_bg == -1) {
|
||||
sgp->sg_cterm_attr = sgp->sg_cterm;
|
||||
} else {
|
||||
at_en.ae_attr = abstract_ui ? sgp->sg_gui : sgp->sg_cterm;
|
||||
at_en.ae_u.cterm.fg_color = sgp->sg_cterm_fg;
|
||||
at_en.ae_u.cterm.bg_color = sgp->sg_cterm_bg;
|
||||
// FIXME(tarruda): The "unset value" for rgb is -1, but since hlgroup is
|
||||
// initialized with 0(by garray functions), check for sg_rgb_{f,b}g_name
|
||||
// before setting attr_entry->{f,g}g_color to a other than -1
|
||||
at_en.fg_color = sgp->sg_rgb_fg_name ? sgp->sg_rgb_fg : -1;
|
||||
at_en.bg_color = sgp->sg_rgb_bg_name ? sgp->sg_rgb_bg : -1;
|
||||
sgp->sg_cterm_attr = get_attr_entry(&cterm_attr_table, &at_en);
|
||||
}
|
||||
at_en.cterm_ae_attr = sgp->sg_cterm;
|
||||
at_en.cterm_fg_color = sgp->sg_cterm_fg;
|
||||
at_en.cterm_bg_color = sgp->sg_cterm_bg;
|
||||
at_en.rgb_ae_attr = sgp->sg_gui;
|
||||
// FIXME(tarruda): The "unset value" for rgb is -1, but since hlgroup is
|
||||
// initialized with 0(by garray functions), check for sg_rgb_{f,b}g_name
|
||||
// before setting attr_entry->{f,g}g_color to a other than -1
|
||||
at_en.rgb_fg_color = sgp->sg_rgb_fg_name ? sgp->sg_rgb_fg : -1;
|
||||
at_en.rgb_bg_color = sgp->sg_rgb_bg_name ? sgp->sg_rgb_bg : -1;
|
||||
sgp->sg_attr = get_attr_entry(&at_en);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -7348,18 +7125,11 @@ static void syn_unadd_group(void)
|
||||
*/
|
||||
int syn_id2attr(int hl_id)
|
||||
{
|
||||
int attr;
|
||||
struct hl_group *sgp;
|
||||
|
||||
hl_id = syn_get_final_id(hl_id);
|
||||
sgp = &HL_TABLE()[hl_id - 1]; /* index is ID minus one */
|
||||
|
||||
if (abstract_ui || t_colors > 1)
|
||||
attr = sgp->sg_cterm_attr;
|
||||
else
|
||||
attr = sgp->sg_term_attr;
|
||||
|
||||
return attr;
|
||||
return sgp->sg_attr;
|
||||
}
|
||||
|
||||
|
||||
@ -7446,11 +7216,12 @@ int highlight_changed(void)
|
||||
* bold-underlined.
|
||||
*/
|
||||
attr = 0;
|
||||
bool colon = false;
|
||||
for (; *p && *p != ','; ++p) { /* parse upto comma */
|
||||
if (vim_iswhite(*p)) /* ignore white space */
|
||||
continue;
|
||||
|
||||
if (attr > HL_ALL) /* Combination with ':' is not allowed. */
|
||||
if (colon) /* Combination with ':' is not allowed. */
|
||||
return FAIL;
|
||||
|
||||
switch (*p) {
|
||||
@ -7472,6 +7243,7 @@ int highlight_changed(void)
|
||||
case ':': ++p; /* highlight group name */
|
||||
if (attr || *p == NUL) /* no combinations */
|
||||
return FAIL;
|
||||
colon = true;
|
||||
end = vim_strchr(p, ',');
|
||||
if (end == NULL)
|
||||
end = p + STRLEN(p);
|
||||
@ -7506,7 +7278,6 @@ int highlight_changed(void)
|
||||
hlcnt = highlight_ga.ga_len;
|
||||
if (id_S == 0) { /* Make sure id_S is always valid to simplify code below */
|
||||
memset(&HL_TABLE()[hlcnt + 9], 0, sizeof(struct hl_group));
|
||||
HL_TABLE()[hlcnt + 9].sg_term = highlight_attr[HLF_S];
|
||||
id_S = hlcnt + 10;
|
||||
}
|
||||
for (int i = 0; i < 9; i++) {
|
||||
@ -7521,7 +7292,6 @@ int highlight_changed(void)
|
||||
highlight_user[i] = syn_id2attr(id);
|
||||
if (id_SNC == 0) {
|
||||
memset(&hlt[hlcnt + i], 0, sizeof(struct hl_group));
|
||||
hlt[hlcnt + i].sg_term = highlight_attr[HLF_SNC];
|
||||
hlt[hlcnt + i].sg_cterm = highlight_attr[HLF_SNC];
|
||||
hlt[hlcnt + i].sg_gui = highlight_attr[HLF_SNC];
|
||||
} else
|
||||
@ -7531,20 +7301,26 @@ int highlight_changed(void)
|
||||
hlt[hlcnt + i].sg_link = 0;
|
||||
|
||||
/* Apply difference between UserX and HLF_S to HLF_SNC */
|
||||
hlt[hlcnt + i].sg_term ^=
|
||||
hlt[id - 1].sg_term ^ hlt[id_S - 1].sg_term;
|
||||
if (hlt[id - 1].sg_start != hlt[id_S - 1].sg_start)
|
||||
hlt[hlcnt + i].sg_start = hlt[id - 1].sg_start;
|
||||
if (hlt[id - 1].sg_stop != hlt[id_S - 1].sg_stop)
|
||||
hlt[hlcnt + i].sg_stop = hlt[id - 1].sg_stop;
|
||||
hlt[hlcnt + i].sg_cterm ^=
|
||||
hlt[id - 1].sg_cterm ^ hlt[id_S - 1].sg_cterm;
|
||||
if (hlt[id - 1].sg_cterm_fg != hlt[id_S - 1].sg_cterm_fg)
|
||||
hlt[hlcnt + i].sg_cterm ^= hlt[id - 1].sg_cterm ^ hlt[id_S - 1].sg_cterm;
|
||||
|
||||
if (hlt[id - 1].sg_cterm_fg != hlt[id_S - 1].sg_cterm_fg) {
|
||||
hlt[hlcnt + i].sg_cterm_fg = hlt[id - 1].sg_cterm_fg;
|
||||
if (hlt[id - 1].sg_cterm_bg != hlt[id_S - 1].sg_cterm_bg)
|
||||
}
|
||||
|
||||
if (hlt[id - 1].sg_cterm_bg != hlt[id_S - 1].sg_cterm_bg) {
|
||||
hlt[hlcnt + i].sg_cterm_bg = hlt[id - 1].sg_cterm_bg;
|
||||
hlt[hlcnt + i].sg_gui ^=
|
||||
hlt[id - 1].sg_gui ^ hlt[id_S - 1].sg_gui;
|
||||
}
|
||||
|
||||
hlt[hlcnt + i].sg_gui ^= hlt[id - 1].sg_gui ^ hlt[id_S - 1].sg_gui;
|
||||
|
||||
if (hlt[id - 1].sg_rgb_fg != hlt[id_S - 1].sg_rgb_fg) {
|
||||
hlt[hlcnt + i].sg_rgb_fg = hlt[id - 1].sg_rgb_fg;
|
||||
}
|
||||
|
||||
if (hlt[id - 1].sg_rgb_bg != hlt[id_S - 1].sg_rgb_bg) {
|
||||
hlt[hlcnt + i].sg_rgb_bg = hlt[id - 1].sg_rgb_bg;
|
||||
}
|
||||
|
||||
highlight_ga.ga_len = hlcnt + i + 1;
|
||||
set_hl_attr(hlcnt + i); /* At long last we can apply */
|
||||
highlight_stlnc[i] = syn_id2attr(hlcnt + i + 1);
|
||||
|
@ -16,7 +16,6 @@
|
||||
#define HL_UNDERLINE 0x08
|
||||
#define HL_UNDERCURL 0x10
|
||||
#define HL_STANDOUT 0x20
|
||||
#define HL_ALL 0x3f
|
||||
|
||||
#define HL_CONTAINED 0x01 /* not used on toplevel */
|
||||
#define HL_TRANSP 0x02 /* has no highlighting */
|
||||
|
@ -67,23 +67,11 @@ struct syn_state {
|
||||
* may have made the state invalid */
|
||||
};
|
||||
|
||||
/*
|
||||
* Structure shared between syntax.c, screen.c and gui_x11.c.
|
||||
*/
|
||||
// Structure shared between syntax.c, screen.c
|
||||
typedef struct attr_entry {
|
||||
short ae_attr; /* HL_BOLD, etc. */
|
||||
RgbValue fg_color, bg_color;
|
||||
union {
|
||||
struct {
|
||||
char_u *start; /* start escape sequence */
|
||||
char_u *stop; /* stop escape sequence */
|
||||
} term;
|
||||
struct {
|
||||
/* These colors need to be > 8 bits to hold 256. */
|
||||
uint16_t fg_color; /* foreground color number */
|
||||
uint16_t bg_color; /* background color number */
|
||||
} cterm;
|
||||
} ae_u;
|
||||
short rgb_ae_attr, cterm_ae_attr; // HL_BOLD, etc.
|
||||
RgbValue rgb_fg_color, rgb_bg_color;
|
||||
int cterm_fg_color, cterm_bg_color;
|
||||
} attrentry_T;
|
||||
|
||||
#endif // NVIM_SYNTAX_DEFS_H
|
||||
|
2771
src/nvim/term.c
2771
src/nvim/term.c
File diff suppressed because it is too large
Load Diff
246
src/nvim/tui/term_input.inl
Normal file
246
src/nvim/tui/term_input.inl
Normal file
@ -0,0 +1,246 @@
|
||||
#include <termkey.h>
|
||||
|
||||
#include "nvim/ascii.h"
|
||||
#include "nvim/os/os.h"
|
||||
#include "nvim/os/input.h"
|
||||
#include "nvim/os/rstream.h"
|
||||
|
||||
|
||||
struct term_input {
|
||||
int in_fd;
|
||||
TermKey *tk;
|
||||
uv_tty_t input_handle;
|
||||
uv_timer_t timer_handle;
|
||||
RBuffer *read_buffer;
|
||||
RStream *read_stream;
|
||||
};
|
||||
|
||||
static void forward_simple_utf8(TermKeyKey *key)
|
||||
{
|
||||
size_t len = 0;
|
||||
char buf[64];
|
||||
char *ptr = key->utf8;
|
||||
|
||||
while (*ptr) {
|
||||
if (*ptr == '<') {
|
||||
len += (size_t)snprintf(buf + len, sizeof(buf) - len, "<lt>");
|
||||
} else {
|
||||
buf[len++] = *ptr;
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
|
||||
buf[len] = 0;
|
||||
input_enqueue((String){.data = buf, .size = len});
|
||||
}
|
||||
|
||||
static void forward_modified_utf8(TermKey *tk, TermKeyKey *key)
|
||||
{
|
||||
size_t len;
|
||||
char buf[64];
|
||||
|
||||
if (key->type == TERMKEY_TYPE_KEYSYM
|
||||
&& key->code.sym == TERMKEY_SYM_ESCAPE) {
|
||||
len = (size_t)snprintf(buf, sizeof(buf), "<Esc>");
|
||||
} else {
|
||||
len = termkey_strfkey(tk, buf, sizeof(buf), key, TERMKEY_FORMAT_VIM);
|
||||
}
|
||||
|
||||
input_enqueue((String){.data = buf, .size = len});
|
||||
}
|
||||
|
||||
static void forward_mouse_event(TermKey *tk, TermKeyKey *key)
|
||||
{
|
||||
char buf[64];
|
||||
size_t len = 0;
|
||||
int button, row, col;
|
||||
TermKeyMouseEvent ev;
|
||||
termkey_interpret_mouse(tk, key, &ev, &button, &row, &col);
|
||||
|
||||
if (ev != TERMKEY_MOUSE_PRESS && ev != TERMKEY_MOUSE_DRAG) {
|
||||
return;
|
||||
}
|
||||
|
||||
row--; col--; // Termkey uses 1-based coordinates
|
||||
buf[len++] = '<';
|
||||
|
||||
if (key->modifiers & TERMKEY_KEYMOD_SHIFT) {
|
||||
len += (size_t)snprintf(buf + len, sizeof(buf) - len, "S-");
|
||||
}
|
||||
|
||||
if (key->modifiers & TERMKEY_KEYMOD_CTRL) {
|
||||
len += (size_t)snprintf(buf + len, sizeof(buf) - len, "C-");
|
||||
}
|
||||
|
||||
if (key->modifiers & TERMKEY_KEYMOD_ALT) {
|
||||
len += (size_t)snprintf(buf + len, sizeof(buf) - len, "A-");
|
||||
}
|
||||
|
||||
if (button == 1) {
|
||||
len += (size_t)snprintf(buf + len, sizeof(buf) - len, "Left");
|
||||
} else if (button == 2) {
|
||||
len += (size_t)snprintf(buf + len, sizeof(buf) - len, "Middle");
|
||||
} else if (button == 3) {
|
||||
len += (size_t)snprintf(buf + len, sizeof(buf) - len, "Right");
|
||||
}
|
||||
|
||||
if (ev == TERMKEY_MOUSE_PRESS) {
|
||||
if (button == 4) {
|
||||
len += (size_t)snprintf(buf + len, sizeof(buf) - len, "ScrollWheelUp");
|
||||
} else if (button == 5) {
|
||||
len += (size_t)snprintf(buf + len, sizeof(buf) - len, "ScrollWheelDown");
|
||||
} else {
|
||||
len += (size_t)snprintf(buf + len, sizeof(buf) - len, "Mouse");
|
||||
}
|
||||
} else if (ev == TERMKEY_MOUSE_DRAG) {
|
||||
len += (size_t)snprintf(buf + len, sizeof(buf) - len, "Drag");
|
||||
}
|
||||
|
||||
len += (size_t)snprintf(buf + len, sizeof(buf) - len, "><%d,%d>", col, row);
|
||||
input_enqueue((String){.data = buf, .size = len});
|
||||
}
|
||||
|
||||
static TermKeyResult tk_getkey(TermKey *tk, TermKeyKey *key, bool force)
|
||||
{
|
||||
return force ? termkey_getkey_force(tk, key) : termkey_getkey(tk, key);
|
||||
}
|
||||
|
||||
static void timer_cb(uv_timer_t *handle);
|
||||
|
||||
static int get_key_code_timeout(void)
|
||||
{
|
||||
Integer ms = 0;
|
||||
bool timeout = false;
|
||||
// Check 'timeout' and 'ttimeout' to determine if we should send ESC
|
||||
// after 'ttimeoutlen'. See :help 'ttimeout' for more information
|
||||
Error err;
|
||||
timeout = vim_get_option(cstr_as_string("timeout"), &err).data.boolean;
|
||||
if (!timeout) {
|
||||
timeout = vim_get_option(cstr_as_string("ttimeout"), &err).data.boolean;
|
||||
}
|
||||
|
||||
if (timeout) {
|
||||
ms = vim_get_option(cstr_as_string("ttimeoutlen"), &err).data.integer;
|
||||
}
|
||||
|
||||
return (int)ms;
|
||||
}
|
||||
|
||||
static void tk_getkeys(TermInput *input, bool force)
|
||||
{
|
||||
TermKeyKey key;
|
||||
TermKeyResult result;
|
||||
|
||||
while ((result = tk_getkey(input->tk, &key, force)) == TERMKEY_RES_KEY) {
|
||||
if (key.type == TERMKEY_TYPE_UNICODE && !key.modifiers) {
|
||||
forward_simple_utf8(&key);
|
||||
} else if (key.type == TERMKEY_TYPE_UNICODE ||
|
||||
key.type == TERMKEY_TYPE_FUNCTION ||
|
||||
key.type == TERMKEY_TYPE_KEYSYM) {
|
||||
forward_modified_utf8(input->tk, &key);
|
||||
} else if (key.type == TERMKEY_TYPE_MOUSE) {
|
||||
forward_mouse_event(input->tk, &key);
|
||||
}
|
||||
}
|
||||
|
||||
if (result != TERMKEY_RES_AGAIN) {
|
||||
return;
|
||||
}
|
||||
|
||||
int ms = get_key_code_timeout();
|
||||
|
||||
if (ms > 0) {
|
||||
// Stop the current timer if already running
|
||||
uv_timer_stop(&input->timer_handle);
|
||||
uv_timer_start(&input->timer_handle, timer_cb, (uint32_t)ms, 0);
|
||||
} else {
|
||||
tk_getkeys(input, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void timer_cb(uv_timer_t *handle)
|
||||
{
|
||||
tk_getkeys(handle->data, true);
|
||||
}
|
||||
|
||||
static void read_cb(RStream *rstream, void *rstream_data, bool eof)
|
||||
{
|
||||
if (eof) {
|
||||
input_done();
|
||||
return;
|
||||
}
|
||||
|
||||
TermInput *input = rstream_data;
|
||||
|
||||
do {
|
||||
char *ptr = rbuffer_read_ptr(input->read_buffer);
|
||||
size_t len = rbuffer_pending(input->read_buffer);
|
||||
if (len > 1 && ptr[0] == ESC && ptr[1] == NUL) {
|
||||
// skip the ESC and NUL and push one <esc> to the input buffer
|
||||
termkey_push_bytes(input->tk, ptr, 1);
|
||||
rbuffer_consumed(input->read_buffer, 2);
|
||||
tk_getkeys(input, true);
|
||||
continue;
|
||||
}
|
||||
// Find the next 'esc' and push everything up to it(excluding)
|
||||
size_t i;
|
||||
for (i = ptr[0] == ESC ? 1 : 0; i < len; i++) {
|
||||
if (ptr[i] == '\x1b') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
size_t consumed = termkey_push_bytes(input->tk, ptr, i);
|
||||
rbuffer_consumed(input->read_buffer, consumed);
|
||||
tk_getkeys(input, false);
|
||||
} while (rbuffer_pending(input->read_buffer));
|
||||
}
|
||||
|
||||
static TermInput *term_input_new(void)
|
||||
{
|
||||
TermInput *rv = xmalloc(sizeof(TermInput));
|
||||
// read input from stderr if stdin is not a tty
|
||||
rv->in_fd = os_isatty(0) ? 0 : (os_isatty(2) ? 2 : 0);
|
||||
|
||||
// Set terminal encoding based on environment(taken from libtermkey source
|
||||
// code)
|
||||
const char *e;
|
||||
int flags = 0;
|
||||
if (((e = os_getenv("LANG")) || (e = os_getenv("LC_MESSAGES"))
|
||||
|| (e = os_getenv("LC_ALL"))) && (e = strchr(e, '.')) && e++ &&
|
||||
(strcasecmp(e, "UTF-8") == 0 || strcasecmp(e, "UTF8") == 0)) {
|
||||
flags |= TERMKEY_FLAG_UTF8;
|
||||
} else {
|
||||
flags |= TERMKEY_FLAG_RAW;
|
||||
}
|
||||
|
||||
rv->tk = termkey_new_abstract(os_getenv("TERM"), flags);
|
||||
int curflags = termkey_get_canonflags(rv->tk);
|
||||
termkey_set_canonflags(rv->tk, curflags | TERMKEY_CANON_DELBS);
|
||||
// setup input handle
|
||||
uv_tty_init(uv_default_loop(), &rv->input_handle, rv->in_fd, 1);
|
||||
uv_tty_set_mode(&rv->input_handle, UV_TTY_MODE_RAW);
|
||||
rv->input_handle.data = NULL;
|
||||
rv->read_buffer = rbuffer_new(0xfff);
|
||||
rv->read_stream = rstream_new(read_cb, rv->read_buffer, rv);
|
||||
rstream_set_stream(rv->read_stream, (uv_stream_t *)&rv->input_handle);
|
||||
rstream_start(rv->read_stream);
|
||||
// initialize a timer handle for handling ESC with libtermkey
|
||||
uv_timer_init(uv_default_loop(), &rv->timer_handle);
|
||||
rv->timer_handle.data = rv;
|
||||
return rv;
|
||||
}
|
||||
|
||||
static void term_input_destroy(TermInput *input)
|
||||
{
|
||||
uv_tty_reset_mode();
|
||||
uv_timer_stop(&input->timer_handle);
|
||||
rstream_stop(input->read_stream);
|
||||
rstream_free(input->read_stream);
|
||||
uv_close((uv_handle_t *)&input->input_handle, NULL);
|
||||
uv_close((uv_handle_t *)&input->timer_handle, NULL);
|
||||
termkey_destroy(input->tk);
|
||||
event_poll(0); // Run once to remove references to input/timer handles
|
||||
free(input->input_handle.data);
|
||||
free(input);
|
||||
}
|
752
src/nvim/tui/tui.c
Normal file
752
src/nvim/tui/tui.c
Normal file
@ -0,0 +1,752 @@
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <uv.h>
|
||||
#include <unibilium.h>
|
||||
|
||||
#include "nvim/lib/kvec.h"
|
||||
|
||||
#include "nvim/vim.h"
|
||||
#include "nvim/ui.h"
|
||||
#include "nvim/map.h"
|
||||
#include "nvim/memory.h"
|
||||
#include "nvim/api/vim.h"
|
||||
#include "nvim/api/private/helpers.h"
|
||||
#include "nvim/os/event.h"
|
||||
#include "nvim/tui/tui.h"
|
||||
|
||||
typedef struct term_input TermInput;
|
||||
|
||||
#include "term_input.inl"
|
||||
|
||||
typedef struct {
|
||||
int top, bot, left, right;
|
||||
} Rect;
|
||||
|
||||
typedef struct {
|
||||
char data[7];
|
||||
HlAttrs attrs;
|
||||
} Cell;
|
||||
|
||||
typedef struct {
|
||||
PMap(cstr_t) *option_cache;
|
||||
unibi_var_t params[9];
|
||||
char buf[0xffff];
|
||||
size_t bufpos;
|
||||
TermInput *input;
|
||||
uv_loop_t *write_loop;
|
||||
unibi_term *ut;
|
||||
uv_tty_t output_handle;
|
||||
uv_signal_t winch_handle;
|
||||
Rect scroll_region;
|
||||
kvec_t(Rect) invalid_regions;
|
||||
int row, col;
|
||||
int bg, fg;
|
||||
int out_fd;
|
||||
int old_height;
|
||||
bool can_use_terminal_scroll;
|
||||
HlAttrs attrs, print_attrs;
|
||||
Cell **screen;
|
||||
struct {
|
||||
size_t enable_mouse, disable_mouse;
|
||||
} unibi_ext;
|
||||
} TUIData;
|
||||
|
||||
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
||||
# include "tui/tui.c.generated.h"
|
||||
#endif
|
||||
|
||||
#define EMPTY_ATTRS ((HlAttrs){false, false, false, false, false, -1, -1})
|
||||
|
||||
#define FOREACH_CELL(ui, top, bot, left, right, go, code) \
|
||||
do { \
|
||||
TUIData *data = ui->data; \
|
||||
for (int row = top; row <= bot; ++row) { \
|
||||
Cell *cells = data->screen[row]; \
|
||||
if (go) { \
|
||||
unibi_goto(ui, row, left); \
|
||||
} \
|
||||
for (int col = left; col <= right; ++col) { \
|
||||
Cell *cell = cells + col; \
|
||||
(void)(cell); \
|
||||
code; \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
||||
void tui_start(void)
|
||||
{
|
||||
TUIData *data = xcalloc(1, sizeof(TUIData));
|
||||
UI *ui = xcalloc(1, sizeof(UI));
|
||||
ui->data = data;
|
||||
data->attrs = data->print_attrs = EMPTY_ATTRS;
|
||||
data->fg = data->bg = -1;
|
||||
data->can_use_terminal_scroll = true;
|
||||
data->bufpos = 0;
|
||||
data->option_cache = pmap_new(cstr_t)();
|
||||
|
||||
// write output to stderr if stdout is not a tty
|
||||
data->out_fd = os_isatty(1) ? 1 : (os_isatty(2) ? 2 : 1);
|
||||
kv_init(data->invalid_regions);
|
||||
// setup term input
|
||||
data->input = term_input_new();
|
||||
// setup unibilium
|
||||
data->ut = unibi_from_env();
|
||||
if (!data->ut) {
|
||||
// For some reason could not read terminfo file, use a dummy entry that
|
||||
// will be populated with common values by fix_terminfo below
|
||||
data->ut = unibi_dummy();
|
||||
}
|
||||
fix_terminfo(data);
|
||||
// Enter alternate screen and clear
|
||||
unibi_out(ui, unibi_enter_ca_mode, NULL);
|
||||
unibi_out(ui, unibi_clear_screen, NULL);
|
||||
|
||||
// setup output handle in a separate event loop(we wanna do synchronous
|
||||
// write to the tty)
|
||||
data->write_loop = xmalloc(sizeof(uv_loop_t));
|
||||
uv_loop_init(data->write_loop);
|
||||
uv_tty_init(data->write_loop, &data->output_handle, data->out_fd, 0);
|
||||
|
||||
// Obtain screen dimensions
|
||||
update_size(ui);
|
||||
|
||||
// listen for SIGWINCH
|
||||
uv_signal_init(uv_default_loop(), &data->winch_handle);
|
||||
uv_signal_start(&data->winch_handle, sigwinch_cb, SIGWINCH);
|
||||
data->winch_handle.data = ui;
|
||||
|
||||
ui->stop = tui_stop;
|
||||
ui->rgb = false;
|
||||
ui->data = data;
|
||||
ui->resize = tui_resize;
|
||||
ui->clear = tui_clear;
|
||||
ui->eol_clear = tui_eol_clear;
|
||||
ui->cursor_goto = tui_cursor_goto;
|
||||
ui->cursor_on = tui_cursor_on;
|
||||
ui->cursor_off = tui_cursor_off;
|
||||
ui->mouse_on = tui_mouse_on;
|
||||
ui->mouse_off = tui_mouse_off;
|
||||
ui->insert_mode = tui_insert_mode;
|
||||
ui->normal_mode = tui_normal_mode;
|
||||
ui->set_scroll_region = tui_set_scroll_region;
|
||||
ui->scroll = tui_scroll;
|
||||
ui->highlight_set = tui_highlight_set;
|
||||
ui->put = tui_put;
|
||||
ui->bell = tui_bell;
|
||||
ui->visual_bell = tui_visual_bell;
|
||||
ui->update_fg = tui_update_fg;
|
||||
ui->update_bg = tui_update_bg;
|
||||
ui->flush = tui_flush;
|
||||
ui->suspend = tui_suspend;
|
||||
ui->set_title = tui_set_title;
|
||||
ui->set_icon = tui_set_icon;
|
||||
// Attach
|
||||
ui_attach(ui);
|
||||
}
|
||||
|
||||
static void tui_stop(UI *ui)
|
||||
{
|
||||
TUIData *data = ui->data;
|
||||
// Destroy common stuff
|
||||
kv_destroy(data->invalid_regions);
|
||||
uv_signal_stop(&data->winch_handle);
|
||||
uv_close((uv_handle_t *)&data->winch_handle, NULL);
|
||||
// Destroy input stuff
|
||||
term_input_destroy(data->input);
|
||||
// Destroy output stuff
|
||||
tui_normal_mode(ui);
|
||||
tui_mouse_off(ui);
|
||||
unibi_out(ui, unibi_exit_attribute_mode, NULL);
|
||||
unibi_out(ui, unibi_cursor_normal, NULL);
|
||||
unibi_out(ui, unibi_exit_ca_mode, NULL);
|
||||
flush_buf(ui);
|
||||
uv_close((uv_handle_t *)&data->output_handle, NULL);
|
||||
uv_run(data->write_loop, UV_RUN_DEFAULT);
|
||||
if (uv_loop_close(data->write_loop)) {
|
||||
abort();
|
||||
}
|
||||
free(data->write_loop);
|
||||
unibi_destroy(data->ut);
|
||||
char *opt_value;
|
||||
map_foreach_value(data->option_cache, opt_value, {
|
||||
free(opt_value);
|
||||
});
|
||||
pmap_free(cstr_t)(data->option_cache);
|
||||
destroy_screen(data);
|
||||
free(data);
|
||||
free(ui);
|
||||
ui_detach(ui);
|
||||
}
|
||||
|
||||
static void try_resize(Event ev)
|
||||
{
|
||||
UI *ui = ev.data;
|
||||
update_size(ui);
|
||||
ui_refresh();
|
||||
}
|
||||
|
||||
static void sigwinch_cb(uv_signal_t *handle, int signum)
|
||||
{
|
||||
// Queue the event because resizing can result in recursive event_poll calls
|
||||
event_push((Event) {
|
||||
.data = handle->data,
|
||||
.handler = try_resize
|
||||
}, false);
|
||||
}
|
||||
|
||||
static bool attrs_differ(HlAttrs a1, HlAttrs a2)
|
||||
{
|
||||
return a1.foreground != a2.foreground || a1.background != a2.background
|
||||
|| a1.bold != a2.bold || a1.italic != a2.italic
|
||||
|| a1.undercurl != a2.undercurl || a1.underline != a2.underline
|
||||
|| a1.reverse != a2.reverse;
|
||||
}
|
||||
|
||||
static void update_attrs(UI *ui, HlAttrs attrs)
|
||||
{
|
||||
TUIData *data = ui->data;
|
||||
unibi_out(ui, unibi_exit_attribute_mode, NULL);
|
||||
|
||||
data->params[0].i = attrs.foreground != -1 ? attrs.foreground : data->fg;
|
||||
if (data->params[0].i != -1) {
|
||||
unibi_out(ui, unibi_set_a_foreground, NULL);
|
||||
}
|
||||
|
||||
data->params[0].i = attrs.background != -1 ? attrs.background : data->bg;
|
||||
if (data->params[0].i != -1) {
|
||||
unibi_out(ui, unibi_set_a_background, NULL);
|
||||
}
|
||||
|
||||
if (attrs.bold) {
|
||||
unibi_out(ui, unibi_enter_bold_mode, NULL);
|
||||
}
|
||||
if (attrs.italic) {
|
||||
unibi_out(ui, unibi_enter_italics_mode, NULL);
|
||||
}
|
||||
if (attrs.underline) {
|
||||
unibi_out(ui, unibi_enter_underline_mode, NULL);
|
||||
}
|
||||
if (attrs.reverse) {
|
||||
unibi_out(ui, unibi_enter_reverse_mode, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void print_cell(UI *ui, Cell *ptr)
|
||||
{
|
||||
TUIData *data = ui->data;
|
||||
if (attrs_differ(ptr->attrs, data->print_attrs)) {
|
||||
update_attrs(ui, ptr->attrs);
|
||||
data->print_attrs = ptr->attrs;
|
||||
}
|
||||
out(ui, ptr->data);
|
||||
}
|
||||
|
||||
static void clear_region(UI *ui, int top, int bot, int left, int right,
|
||||
bool refresh)
|
||||
{
|
||||
TUIData *data = ui->data;
|
||||
HlAttrs clear_attrs = EMPTY_ATTRS;
|
||||
clear_attrs.foreground = data->fg;
|
||||
clear_attrs.background = data->bg;
|
||||
|
||||
bool cleared = false;
|
||||
if (refresh && data->bg == -1 && right == ui->width -1) {
|
||||
// Background is set to the default color and the right edge matches the
|
||||
// screen end, try to use terminal codes for clearing the requested area.
|
||||
if (left == 0) {
|
||||
if (bot == ui->height - 1) {
|
||||
if (top == 0) {
|
||||
unibi_out(ui, unibi_clear_screen, NULL);
|
||||
} else {
|
||||
unibi_goto(ui, top, 0);
|
||||
unibi_out(ui, unibi_clr_eos, NULL);
|
||||
}
|
||||
cleared = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!cleared) {
|
||||
// iterate through each line and clear with clr_eol
|
||||
for (int row = top; row <= bot; ++row) {
|
||||
unibi_goto(ui, row, left);
|
||||
unibi_out(ui, unibi_clr_eol, NULL);
|
||||
}
|
||||
cleared = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool clear = refresh && !cleared;
|
||||
FOREACH_CELL(ui, top, bot, left, right, clear, {
|
||||
cell->data[0] = ' ';
|
||||
cell->data[1] = 0;
|
||||
cell->attrs = clear_attrs;
|
||||
if (clear) {
|
||||
print_cell(ui, cell);
|
||||
}
|
||||
});
|
||||
|
||||
// restore cursor
|
||||
unibi_goto(ui, data->row, data->col);
|
||||
}
|
||||
|
||||
static void tui_resize(UI *ui, int width, int height)
|
||||
{
|
||||
TUIData *data = ui->data;
|
||||
destroy_screen(data);
|
||||
|
||||
data->screen = xmalloc((size_t)height * sizeof(Cell *));
|
||||
for (int i = 0; i < height; i++) {
|
||||
data->screen[i] = xcalloc((size_t)width, sizeof(Cell));
|
||||
}
|
||||
|
||||
data->old_height = height;
|
||||
data->scroll_region.top = 0;
|
||||
data->scroll_region.bot = height - 1;
|
||||
data->scroll_region.left = 0;
|
||||
data->scroll_region.right = width - 1;
|
||||
data->row = data->col = 0;
|
||||
}
|
||||
|
||||
static void tui_clear(UI *ui)
|
||||
{
|
||||
TUIData *data = ui->data;
|
||||
clear_region(ui, data->scroll_region.top, data->scroll_region.bot,
|
||||
data->scroll_region.left, data->scroll_region.right, true);
|
||||
}
|
||||
|
||||
static void tui_eol_clear(UI *ui)
|
||||
{
|
||||
TUIData *data = ui->data;
|
||||
clear_region(ui, data->row, data->row, data->col,
|
||||
data->scroll_region.right, true);
|
||||
}
|
||||
|
||||
static void tui_cursor_goto(UI *ui, int row, int col)
|
||||
{
|
||||
TUIData *data = ui->data;
|
||||
data->row = row;
|
||||
data->col = col;
|
||||
unibi_goto(ui, row, col);
|
||||
}
|
||||
|
||||
static void tui_cursor_on(UI *ui)
|
||||
{
|
||||
unibi_out(ui, unibi_cursor_normal, NULL);
|
||||
}
|
||||
|
||||
static void tui_cursor_off(UI *ui)
|
||||
{
|
||||
unibi_out(ui, unibi_cursor_invisible, NULL);
|
||||
}
|
||||
|
||||
static void tui_mouse_on(UI *ui)
|
||||
{
|
||||
TUIData *data = ui->data;
|
||||
unibi_out(ui, (int)data->unibi_ext.enable_mouse, NULL);
|
||||
}
|
||||
|
||||
static void tui_mouse_off(UI *ui)
|
||||
{
|
||||
TUIData *data = ui->data;
|
||||
unibi_out(ui, (int)data->unibi_ext.disable_mouse, NULL);
|
||||
}
|
||||
|
||||
static void tui_insert_mode(UI *ui)
|
||||
{
|
||||
unibi_out(ui, -1, "t_SI");
|
||||
}
|
||||
|
||||
static void tui_normal_mode(UI *ui)
|
||||
{
|
||||
unibi_out(ui, -1, "t_EI");
|
||||
}
|
||||
|
||||
static void tui_set_scroll_region(UI *ui, int top, int bot, int left,
|
||||
int right)
|
||||
{
|
||||
TUIData *data = ui->data;
|
||||
data->scroll_region.top = top;
|
||||
data->scroll_region.bot = bot;
|
||||
data->scroll_region.left = left;
|
||||
data->scroll_region.right = right;
|
||||
|
||||
data->can_use_terminal_scroll =
|
||||
left == 0 && right == ui->width - 1
|
||||
&& ((top == 0 && bot == ui->height - 1)
|
||||
|| unibi_get_str(data->ut, unibi_change_scroll_region));
|
||||
}
|
||||
|
||||
static void tui_scroll(UI *ui, int count)
|
||||
{
|
||||
TUIData *data = ui->data;
|
||||
int top = data->scroll_region.top;
|
||||
int bot = data->scroll_region.bot;
|
||||
int left = data->scroll_region.left;
|
||||
int right = data->scroll_region.right;
|
||||
|
||||
if (data->can_use_terminal_scroll) {
|
||||
// Change terminal scroll region and move cursor to the top
|
||||
data->params[0].i = top;
|
||||
data->params[1].i = bot;
|
||||
unibi_out(ui, unibi_change_scroll_region, NULL);
|
||||
unibi_goto(ui, top, left);
|
||||
}
|
||||
|
||||
// Compute start/stop/step for the loop below, also use terminal scroll
|
||||
// if possible
|
||||
int start, stop, step;
|
||||
if (count > 0) {
|
||||
start = top;
|
||||
stop = bot - count + 1;
|
||||
step = 1;
|
||||
if (data->can_use_terminal_scroll) {
|
||||
if (count == 1) {
|
||||
unibi_out(ui, unibi_delete_line, NULL);
|
||||
} else {
|
||||
data->params[0].i = count;
|
||||
unibi_out(ui, unibi_parm_delete_line, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
start = bot;
|
||||
stop = top - count - 1;
|
||||
step = -1;
|
||||
if (data->can_use_terminal_scroll) {
|
||||
if (count == -1) {
|
||||
unibi_out(ui, unibi_insert_line, NULL);
|
||||
} else {
|
||||
data->params[0].i = -count;
|
||||
unibi_out(ui, unibi_parm_insert_line, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (data->can_use_terminal_scroll) {
|
||||
// Restore terminal scroll region and cursor
|
||||
data->params[0].i = 0;
|
||||
data->params[1].i = ui->height - 1;
|
||||
unibi_out(ui, unibi_change_scroll_region, NULL);
|
||||
unibi_goto(ui, data->row, data->col);
|
||||
}
|
||||
|
||||
int i;
|
||||
// Scroll internal screen
|
||||
for (i = start; i != stop; i += step) {
|
||||
Cell *target_row = data->screen[i] + left;
|
||||
Cell *source_row = data->screen[i + count] + left;
|
||||
memcpy(target_row, source_row, sizeof(Cell) * (size_t)(right - left + 1));
|
||||
}
|
||||
|
||||
// clear emptied region, updating the terminal if its builtin scrolling
|
||||
// facility was used. This is done when the background color is not the
|
||||
// default, since scrolling may leave wrong background in the cleared area.
|
||||
bool update_clear = data->bg != -1 && data->can_use_terminal_scroll;
|
||||
if (count > 0) {
|
||||
clear_region(ui, stop, stop + count - 1, left, right, update_clear);
|
||||
} else {
|
||||
clear_region(ui, stop + count + 1, stop, left, right, update_clear);
|
||||
}
|
||||
|
||||
if (!data->can_use_terminal_scroll) {
|
||||
// Mark the entire scroll region as invalid for redrawing later
|
||||
invalidate(ui, data->scroll_region.top, data->scroll_region.bot,
|
||||
data->scroll_region.left, data->scroll_region.right);
|
||||
}
|
||||
}
|
||||
|
||||
static void tui_highlight_set(UI *ui, HlAttrs attrs)
|
||||
{
|
||||
((TUIData *)ui->data)->attrs = attrs;
|
||||
}
|
||||
|
||||
static void tui_put(UI *ui, uint8_t *text, size_t size)
|
||||
{
|
||||
TUIData *data = ui->data;
|
||||
Cell *cell = data->screen[data->row] + data->col;
|
||||
cell->data[size] = 0;
|
||||
cell->attrs = data->attrs;
|
||||
|
||||
if (text) {
|
||||
memcpy(cell->data, text, size);
|
||||
}
|
||||
|
||||
print_cell(ui, cell);
|
||||
data->col += 1;
|
||||
}
|
||||
|
||||
static void tui_bell(UI *ui)
|
||||
{
|
||||
unibi_out(ui, unibi_bell, NULL);
|
||||
}
|
||||
|
||||
static void tui_visual_bell(UI *ui)
|
||||
{
|
||||
unibi_out(ui, unibi_flash_screen, NULL);
|
||||
}
|
||||
|
||||
static void tui_update_fg(UI *ui, int fg)
|
||||
{
|
||||
((TUIData *)ui->data)->fg = fg;
|
||||
}
|
||||
|
||||
static void tui_update_bg(UI *ui, int bg)
|
||||
{
|
||||
((TUIData *)ui->data)->bg = bg;
|
||||
}
|
||||
|
||||
static void tui_flush(UI *ui)
|
||||
{
|
||||
TUIData *data = ui->data;
|
||||
|
||||
while (kv_size(data->invalid_regions)) {
|
||||
Rect r = kv_pop(data->invalid_regions);
|
||||
FOREACH_CELL(ui, r.top, r.bot, r.left, r.right, true, {
|
||||
print_cell(ui, cell);
|
||||
});
|
||||
}
|
||||
|
||||
unibi_goto(ui, data->row, data->col);
|
||||
flush_buf(ui);
|
||||
}
|
||||
|
||||
static void tui_suspend(UI *ui)
|
||||
{
|
||||
tui_stop(ui);
|
||||
kill(0, SIGTSTP);
|
||||
tui_start();
|
||||
}
|
||||
|
||||
static void tui_set_title(UI *ui, char *title)
|
||||
{
|
||||
TUIData *data = ui->data;
|
||||
if (!(unibi_get_str(data->ut, unibi_to_status_line)
|
||||
&& unibi_get_str(data->ut, unibi_from_status_line))) {
|
||||
return;
|
||||
}
|
||||
unibi_out(ui, unibi_to_status_line, NULL);
|
||||
out(ui, title);
|
||||
unibi_out(ui, unibi_from_status_line, NULL);
|
||||
}
|
||||
|
||||
static void tui_set_icon(UI *ui, char *icon)
|
||||
{
|
||||
}
|
||||
|
||||
static void invalidate(UI *ui, int top, int bot, int left, int right)
|
||||
{
|
||||
TUIData *data = ui->data;
|
||||
Rect *intersects = NULL;
|
||||
// Increase dimensions before comparing to ensure adjacent regions are
|
||||
// treated as intersecting
|
||||
--top;
|
||||
++bot;
|
||||
--left;
|
||||
++right;
|
||||
|
||||
for (size_t i = 0; i < kv_size(data->invalid_regions); i++) {
|
||||
Rect *r = &kv_A(data->invalid_regions, i);
|
||||
if (!(top > r->bot || bot < r->top
|
||||
|| left > r->right || right < r->left)) {
|
||||
intersects = r;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
++top;
|
||||
--bot;
|
||||
++left;
|
||||
--right;
|
||||
|
||||
if (intersects) {
|
||||
// If top/bot/left/right intersects with a invalid rect, we replace it
|
||||
// by the union
|
||||
intersects->top = MIN(top, intersects->top);
|
||||
intersects->bot = MAX(bot, intersects->bot);
|
||||
intersects->left = MIN(left, intersects->left);
|
||||
intersects->right = MAX(right, intersects->right);
|
||||
} else {
|
||||
// Else just add a new entry;
|
||||
kv_push(Rect, data->invalid_regions, ((Rect){top, bot, left, right}));
|
||||
}
|
||||
}
|
||||
|
||||
static void update_size(UI *ui)
|
||||
{
|
||||
TUIData *data = ui->data;
|
||||
int width = 0, height = 0;
|
||||
// 1 - try from a system call(ioctl/TIOCGWINSZ on unix)
|
||||
if (!uv_tty_get_winsize(&data->output_handle, &width, &height)) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
// 2 - use $LINES/$COLUMNS if available
|
||||
const char *val;
|
||||
int advance;
|
||||
if ((val = os_getenv("LINES"))
|
||||
&& sscanf(val, "%d%n", &height, &advance) != EOF && advance
|
||||
&& (val = os_getenv("COLUMNS"))
|
||||
&& sscanf(val, "%d%n", &width, &advance) != EOF && advance) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
// 3- read from terminfo if available
|
||||
height = unibi_get_num(data->ut, unibi_lines);
|
||||
width = unibi_get_num(data->ut, unibi_columns);
|
||||
|
||||
end:
|
||||
if (width <= 0 || height <= 0) {
|
||||
// use a default of 80x24
|
||||
width = 80;
|
||||
height = 24;
|
||||
}
|
||||
|
||||
ui->width = width;
|
||||
ui->height = height;
|
||||
}
|
||||
|
||||
static void unibi_goto(UI *ui, int row, int col)
|
||||
{
|
||||
TUIData *data = ui->data;
|
||||
data->params[0].i = row;
|
||||
data->params[1].i = col;
|
||||
unibi_out(ui, unibi_cursor_address, NULL);
|
||||
}
|
||||
|
||||
static void unibi_out(UI *ui, int unibi_index, char *nvim_override)
|
||||
{
|
||||
TUIData *data = ui->data;
|
||||
|
||||
const char *str = NULL;
|
||||
|
||||
if (nvim_override) {
|
||||
str = get_term_option(ui, nvim_override);
|
||||
} else if (unibi_index >= 0) {
|
||||
if (unibi_index < unibi_string_begin_) {
|
||||
str = unibi_get_ext_str(data->ut, (unsigned)unibi_index);
|
||||
} else {
|
||||
str = unibi_get_str(data->ut, (unsigned)unibi_index);
|
||||
}
|
||||
}
|
||||
|
||||
if (str) {
|
||||
data->bufpos += unibi_run(str, data->params, data->buf + data->bufpos,
|
||||
sizeof(data->buf) - data->bufpos);
|
||||
}
|
||||
}
|
||||
|
||||
static void out(UI *ui, const char *str)
|
||||
{
|
||||
TUIData *data = ui->data;
|
||||
data->bufpos += (size_t)snprintf(data->buf + data->bufpos,
|
||||
sizeof(data->buf) - data->bufpos, "%s", str);
|
||||
}
|
||||
|
||||
static void unibi_set_if_empty(unibi_term *ut, enum unibi_string str,
|
||||
const char *val)
|
||||
{
|
||||
if (!unibi_get_str(ut, str)) {
|
||||
unibi_set_str(ut, str, val);
|
||||
}
|
||||
}
|
||||
|
||||
static void fix_terminfo(TUIData *data)
|
||||
{
|
||||
unibi_term *ut = data->ut;
|
||||
|
||||
const char *term = os_getenv("TERM");
|
||||
if (!term) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
#define STARTS_WITH(str, prefix) (!memcmp(str, prefix, sizeof(prefix) - 1))
|
||||
|
||||
if (STARTS_WITH(term, "rxvt")) {
|
||||
unibi_set_if_empty(ut, unibi_exit_attribute_mode, "\x1b[m\x1b(B");
|
||||
unibi_set_if_empty(ut, unibi_flash_screen, "\x1b[?5h$<20/>\x1b[?5l");
|
||||
unibi_set_if_empty(ut, unibi_enter_italics_mode, "\x1b[3m");
|
||||
} else if (STARTS_WITH(term, "screen")) {
|
||||
unibi_set_if_empty(ut, unibi_to_status_line, "\x1b_");
|
||||
unibi_set_if_empty(ut, unibi_from_status_line, "\x1b\\");
|
||||
}
|
||||
|
||||
if (STARTS_WITH(term, "xterm") || STARTS_WITH(term, "rxvt")) {
|
||||
unibi_set_if_empty(ut, unibi_cursor_normal, "\x1b[?12l\x1b[?25h");
|
||||
unibi_set_if_empty(ut, unibi_cursor_invisible, "\x1b[?25l");
|
||||
unibi_set_if_empty(ut, unibi_flash_screen, "\x1b[?5h$<100/>\x1b[?5l");
|
||||
unibi_set_if_empty(ut, unibi_exit_attribute_mode, "\x1b(B\x1b[m");
|
||||
unibi_set_if_empty(ut, unibi_change_scroll_region, "\x1b[%i%p1%d;%p2%dr");
|
||||
unibi_set_if_empty(ut, unibi_clear_screen, "\x1b[H\x1b[2J");
|
||||
unibi_set_if_empty(ut, unibi_to_status_line, "\x1b]2");
|
||||
unibi_set_if_empty(ut, unibi_from_status_line, "\x07");
|
||||
}
|
||||
|
||||
end:
|
||||
// Fill some empty slots with common terminal strings
|
||||
data->unibi_ext.enable_mouse = unibi_add_ext_str(ut, NULL,
|
||||
"\x1b[?1002h\x1b[?1006h");
|
||||
data->unibi_ext.disable_mouse = unibi_add_ext_str(ut, NULL,
|
||||
"\x1b[?1002l\x1b[?1006l");
|
||||
|
||||
unibi_set_if_empty(ut, unibi_cursor_address, "\x1b[%i%p1%d;%p2%dH");
|
||||
unibi_set_if_empty(ut, unibi_exit_attribute_mode, "\x1b[0;10m");
|
||||
unibi_set_if_empty(ut, unibi_set_a_foreground,
|
||||
"\x1b[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m");
|
||||
unibi_set_if_empty(ut, unibi_set_a_background,
|
||||
"\x1b[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48;5;%p1%d%;m");
|
||||
unibi_set_if_empty(ut, unibi_enter_bold_mode, "\x1b[1m");
|
||||
unibi_set_if_empty(ut, unibi_enter_underline_mode, "\x1b[4m");
|
||||
unibi_set_if_empty(ut, unibi_enter_reverse_mode, "\x1b[7m");
|
||||
unibi_set_if_empty(ut, unibi_bell, "\x07");
|
||||
unibi_set_if_empty(data->ut, unibi_enter_ca_mode, "\x1b[?1049h");
|
||||
unibi_set_if_empty(data->ut, unibi_exit_ca_mode, "\x1b[?1049l");
|
||||
unibi_set_if_empty(ut, unibi_delete_line, "\x1b[M");
|
||||
unibi_set_if_empty(ut, unibi_parm_delete_line, "\x1b[%p1%dM");
|
||||
unibi_set_if_empty(ut, unibi_insert_line, "\x1b[L");
|
||||
unibi_set_if_empty(ut, unibi_parm_insert_line, "\x1b[%p1%dL");
|
||||
unibi_set_if_empty(ut, unibi_clear_screen, "\x1b[H\x1b[J");
|
||||
unibi_set_if_empty(ut, unibi_clr_eol, "\x1b[K");
|
||||
unibi_set_if_empty(ut, unibi_clr_eos, "\x1b[J");
|
||||
}
|
||||
|
||||
static void flush_buf(UI *ui)
|
||||
{
|
||||
static uv_write_t req;
|
||||
static uv_buf_t buf;
|
||||
TUIData *data = ui->data;
|
||||
buf.base = data->buf;
|
||||
buf.len = data->bufpos;
|
||||
uv_write(&req, (uv_stream_t *)&data->output_handle, &buf, 1, NULL);
|
||||
uv_run(data->write_loop, UV_RUN_DEFAULT);
|
||||
data->bufpos = 0;
|
||||
}
|
||||
|
||||
static char *get_term_option(UI *ui, char *option)
|
||||
{
|
||||
TUIData *data = ui->data;
|
||||
|
||||
char *rv = pmap_get(cstr_t)(data->option_cache, option);
|
||||
if (!rv) {
|
||||
Error err;
|
||||
Object val = vim_get_option(cstr_as_string(option), &err);
|
||||
if (val.type == kObjectTypeString) {
|
||||
rv = val.data.string.data;
|
||||
pmap_put(cstr_t)(data->option_cache, option, rv);
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static void destroy_screen(TUIData *data)
|
||||
{
|
||||
if (data->screen) {
|
||||
for (int i = 0; i < data->old_height; i++) {
|
||||
free(data->screen[i]);
|
||||
}
|
||||
free(data->screen);
|
||||
}
|
||||
}
|
8
src/nvim/tui/tui.h
Normal file
8
src/nvim/tui/tui.h
Normal file
@ -0,0 +1,8 @@
|
||||
#ifndef NVIM_TUI_TUI_H
|
||||
#define NVIM_TUI_TUI_H
|
||||
|
||||
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
||||
# include "tui/tui.h.generated.h"
|
||||
#endif
|
||||
|
||||
#endif // NVIM_TUI_TUI_H
|
211
src/nvim/ui.c
211
src/nvim/ui.c
@ -46,6 +46,7 @@
|
||||
#include "nvim/syntax.h"
|
||||
#include "nvim/term.h"
|
||||
#include "nvim/window.h"
|
||||
#include "nvim/tui/tui.h"
|
||||
|
||||
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
||||
# include "ui.c.generated.h"
|
||||
@ -59,8 +60,8 @@ static int row, col;
|
||||
static struct {
|
||||
int top, bot, left, right;
|
||||
} sr;
|
||||
static int current_highlight_mask = 0;
|
||||
static bool cursor_enabled = true;
|
||||
static int current_attr_code = 0;
|
||||
static bool cursor_enabled = true, pending_cursor_update = false;
|
||||
static int height, width;
|
||||
|
||||
// This set of macros allow us to use UI_CALL to invoke any function on
|
||||
@ -71,6 +72,7 @@ static int height, width;
|
||||
// works.
|
||||
#define UI_CALL(...) \
|
||||
do { \
|
||||
flush_cursor_update(); \
|
||||
for (size_t i = 0; i < ui_count; i++) { \
|
||||
UI *ui = uis[i]; \
|
||||
UI_CALL_HELPER(CNT(__VA_ARGS__), __VA_ARGS__); \
|
||||
@ -80,8 +82,18 @@ static int height, width;
|
||||
#define SELECT_NTH(a1, a2, a3, a4, a5, a6, ...) a6
|
||||
#define UI_CALL_HELPER(c, ...) UI_CALL_HELPER2(c, __VA_ARGS__)
|
||||
#define UI_CALL_HELPER2(c, ...) UI_CALL_##c(__VA_ARGS__)
|
||||
#define UI_CALL_MORE(method, ...) ui->method(ui, __VA_ARGS__)
|
||||
#define UI_CALL_ZERO(method) ui->method(ui)
|
||||
#define UI_CALL_MORE(method, ...) if (ui->method) ui->method(ui, __VA_ARGS__)
|
||||
#define UI_CALL_ZERO(method) if (ui->method) ui->method(ui)
|
||||
|
||||
void ui_builtin_start(void)
|
||||
{
|
||||
tui_start();
|
||||
}
|
||||
|
||||
void ui_builtin_stop(void)
|
||||
{
|
||||
UI_CALL(stop);
|
||||
}
|
||||
|
||||
void ui_write(uint8_t *s, int len)
|
||||
{
|
||||
@ -90,28 +102,7 @@ void ui_write(uint8_t *s, int len)
|
||||
return;
|
||||
}
|
||||
|
||||
if (abstract_ui) {
|
||||
parse_abstract_ui_codes(s, len);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!len) {
|
||||
return;
|
||||
}
|
||||
|
||||
char_u *tofree = NULL;
|
||||
|
||||
if (output_conv.vc_type != CONV_NONE) {
|
||||
/* Convert characters from 'encoding' to 'termencoding'. */
|
||||
tofree = string_convert(&output_conv, s, &len);
|
||||
if (tofree != NULL)
|
||||
s = tofree;
|
||||
}
|
||||
|
||||
term_write(s, len);
|
||||
|
||||
if (output_conv.vc_type != CONV_NONE)
|
||||
free(tofree);
|
||||
parse_abstract_ui_codes(s, len);
|
||||
}
|
||||
|
||||
bool ui_rgb_attached(void)
|
||||
@ -124,6 +115,11 @@ bool ui_rgb_attached(void)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ui_active(void)
|
||||
{
|
||||
return ui_count != 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the machine has job control, use it to suspend the program,
|
||||
* otherwise fake it by starting a new shell.
|
||||
@ -131,12 +127,8 @@ bool ui_rgb_attached(void)
|
||||
*/
|
||||
void ui_suspend(void)
|
||||
{
|
||||
if (abstract_ui) {
|
||||
UI_CALL(suspend);
|
||||
UI_CALL(flush);
|
||||
} else {
|
||||
mch_suspend();
|
||||
}
|
||||
UI_CALL(suspend);
|
||||
UI_CALL(flush);
|
||||
}
|
||||
|
||||
void ui_set_title(char *title)
|
||||
@ -151,47 +143,17 @@ void ui_set_icon(char *icon)
|
||||
UI_CALL(flush);
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to get the current Vim shell size. Put the result in Rows and Columns.
|
||||
* Use the new sizes as defaults for 'columns' and 'lines'.
|
||||
* Return OK when size could be determined, FAIL otherwise.
|
||||
*/
|
||||
int ui_get_shellsize(void)
|
||||
{
|
||||
if (abstract_ui) {
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
int retval;
|
||||
|
||||
retval = mch_get_shellsize();
|
||||
|
||||
check_shellsize();
|
||||
|
||||
/* adjust the default for 'lines' and 'columns' */
|
||||
if (retval == OK) {
|
||||
set_number_default("lines", Rows);
|
||||
set_number_default("columns", Columns);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* May update the shape of the cursor.
|
||||
*/
|
||||
void ui_cursor_shape(void)
|
||||
{
|
||||
if (abstract_ui) {
|
||||
ui_change_mode();
|
||||
} else {
|
||||
term_cursor_shape();
|
||||
conceal_check_cursur_line();
|
||||
}
|
||||
ui_change_mode();
|
||||
}
|
||||
|
||||
void ui_refresh(void)
|
||||
{
|
||||
if (!ui_count) {
|
||||
if (!ui_active()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -203,7 +165,7 @@ void ui_refresh(void)
|
||||
height = ui->height < height ? ui->height : height;
|
||||
}
|
||||
|
||||
screen_resize(width, height, true);
|
||||
screen_resize(width, height);
|
||||
}
|
||||
|
||||
void ui_resize(int new_width, int new_height)
|
||||
@ -241,20 +203,12 @@ void ui_cursor_off(void)
|
||||
|
||||
void ui_mouse_on(void)
|
||||
{
|
||||
if (abstract_ui) {
|
||||
UI_CALL(mouse_on);
|
||||
} else {
|
||||
mch_setmouse(true);
|
||||
}
|
||||
UI_CALL(mouse_on);
|
||||
}
|
||||
|
||||
void ui_mouse_off(void)
|
||||
{
|
||||
if (abstract_ui) {
|
||||
UI_CALL(mouse_off);
|
||||
} else {
|
||||
mch_setmouse(false);
|
||||
}
|
||||
UI_CALL(mouse_off);
|
||||
}
|
||||
|
||||
// Notify that the current mode has changed. Can be used to change cursor
|
||||
@ -319,77 +273,82 @@ void ui_detach(UI *ui)
|
||||
}
|
||||
}
|
||||
|
||||
static void highlight_start(int mask)
|
||||
static void highlight_start(int attr_code)
|
||||
{
|
||||
if (mask > HL_ALL) {
|
||||
// attribute code
|
||||
current_highlight_mask = mask;
|
||||
} else {
|
||||
// attribute mask
|
||||
current_highlight_mask |= mask;
|
||||
}
|
||||
current_attr_code = attr_code;
|
||||
|
||||
if (!ui_count) {
|
||||
return;
|
||||
}
|
||||
|
||||
set_highlight_args(current_highlight_mask);
|
||||
set_highlight_args(current_attr_code);
|
||||
}
|
||||
|
||||
static void highlight_stop(int mask)
|
||||
{
|
||||
if (mask > HL_ALL) {
|
||||
// attribute code
|
||||
current_highlight_mask = HL_NORMAL;
|
||||
} else {
|
||||
// attribute mask
|
||||
current_highlight_mask &= ~mask;
|
||||
current_attr_code = HL_NORMAL;
|
||||
|
||||
if (!ui_count) {
|
||||
return;
|
||||
}
|
||||
|
||||
set_highlight_args(current_highlight_mask);
|
||||
set_highlight_args(current_attr_code);
|
||||
}
|
||||
|
||||
static void set_highlight_args(int mask)
|
||||
static void set_highlight_args(int attr_code)
|
||||
{
|
||||
HlAttrs rgb_attrs = { false, false, false, false, false, -1, -1 };
|
||||
attrentry_T *aep = NULL;
|
||||
|
||||
if (mask > HL_ALL) {
|
||||
aep = syn_cterm_attr2entry(mask);
|
||||
mask = aep ? aep->ae_attr : 0;
|
||||
}
|
||||
|
||||
rgb_attrs.bold = mask & HL_BOLD;
|
||||
rgb_attrs.underline = mask & HL_UNDERLINE;
|
||||
rgb_attrs.undercurl = mask & HL_UNDERCURL;
|
||||
rgb_attrs.italic = mask & HL_ITALIC;
|
||||
rgb_attrs.reverse = mask & (HL_INVERSE | HL_STANDOUT);
|
||||
HlAttrs cterm_attrs = rgb_attrs;
|
||||
|
||||
if (aep) {
|
||||
if (aep->fg_color != normal_fg) {
|
||||
rgb_attrs.foreground = aep->fg_color;
|
||||
}
|
||||
|
||||
if (aep->bg_color != normal_bg) {
|
||||
rgb_attrs.background = aep->bg_color;
|
||||
}
|
||||
|
||||
if (cterm_normal_fg_color != aep->ae_u.cterm.fg_color) {
|
||||
cterm_attrs.foreground = aep->ae_u.cterm.fg_color - 1;
|
||||
}
|
||||
|
||||
if (cterm_normal_bg_color != aep->ae_u.cterm.bg_color) {
|
||||
cterm_attrs.background = aep->ae_u.cterm.bg_color - 1;
|
||||
}
|
||||
if (attr_code == HL_NORMAL) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
int rgb_mask = 0;
|
||||
int cterm_mask = 0;
|
||||
attrentry_T *aep = syn_cterm_attr2entry(attr_code);
|
||||
|
||||
if (!aep) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
rgb_mask = aep->rgb_ae_attr;
|
||||
cterm_mask = aep->cterm_ae_attr;
|
||||
|
||||
rgb_attrs.bold = rgb_mask & HL_BOLD;
|
||||
rgb_attrs.underline = rgb_mask & HL_UNDERLINE;
|
||||
rgb_attrs.undercurl = rgb_mask & HL_UNDERCURL;
|
||||
rgb_attrs.italic = rgb_mask & HL_ITALIC;
|
||||
rgb_attrs.reverse = rgb_mask & (HL_INVERSE | HL_STANDOUT);
|
||||
cterm_attrs.bold = cterm_mask & HL_BOLD;
|
||||
cterm_attrs.underline = cterm_mask & HL_UNDERLINE;
|
||||
cterm_attrs.undercurl = cterm_mask & HL_UNDERCURL;
|
||||
cterm_attrs.italic = cterm_mask & HL_ITALIC;
|
||||
cterm_attrs.reverse = cterm_mask & (HL_INVERSE | HL_STANDOUT);
|
||||
|
||||
if (aep->rgb_fg_color != normal_fg) {
|
||||
rgb_attrs.foreground = aep->rgb_fg_color;
|
||||
}
|
||||
|
||||
if (aep->rgb_bg_color != normal_bg) {
|
||||
rgb_attrs.background = aep->rgb_bg_color;
|
||||
}
|
||||
|
||||
if (cterm_normal_fg_color != aep->cterm_fg_color) {
|
||||
cterm_attrs.foreground = aep->cterm_fg_color - 1;
|
||||
}
|
||||
|
||||
if (cterm_normal_bg_color != aep->cterm_bg_color) {
|
||||
cterm_attrs.background = aep->cterm_bg_color - 1;
|
||||
}
|
||||
|
||||
end:
|
||||
UI_CALL(highlight_set, (ui->rgb ? rgb_attrs : cterm_attrs));
|
||||
}
|
||||
|
||||
static void parse_abstract_ui_codes(uint8_t *ptr, int len)
|
||||
{
|
||||
if (!ui_count) {
|
||||
if (!ui_active()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -558,5 +517,13 @@ static void ui_cursor_goto(int new_row, int new_col)
|
||||
}
|
||||
row = new_row;
|
||||
col = new_col;
|
||||
UI_CALL(cursor_goto, row, col);
|
||||
pending_cursor_update = true;
|
||||
}
|
||||
|
||||
static void flush_cursor_update(void)
|
||||
{
|
||||
if (pending_cursor_update) {
|
||||
pending_cursor_update = false;
|
||||
UI_CALL(cursor_goto, row, col);
|
||||
}
|
||||
}
|
||||
|
@ -38,6 +38,7 @@ struct ui_t {
|
||||
void (*suspend)(UI *ui);
|
||||
void (*set_title)(UI *ui, char *title);
|
||||
void (*set_icon)(UI *ui, char *icon);
|
||||
void (*stop)(UI *ui);
|
||||
};
|
||||
|
||||
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
||||
|
@ -136,21 +136,6 @@ static char *(features[]) = {
|
||||
"+tag_binary",
|
||||
"+tag_old_static",
|
||||
"-tag_any_white",
|
||||
#if defined(UNIX)
|
||||
|
||||
// only Unix can have terminfo instead of termcap
|
||||
# ifdef TERMINFO
|
||||
"+terminfo",
|
||||
# else // ifdef TERMINFO
|
||||
"-terminfo",
|
||||
# endif // ifdef TERMINFO
|
||||
#else // unix always includes termcap support
|
||||
# ifdef HAVE_TGETENT
|
||||
"+tgetent",
|
||||
# else // ifdef HAVE_TGETENT
|
||||
"-tgetent",
|
||||
# endif // ifdef HAVE_TGETENT
|
||||
#endif // if defined(UNIX)
|
||||
"+termresponse",
|
||||
"+textobjects",
|
||||
"+title",
|
||||
@ -813,19 +798,6 @@ static char *(extra_patches[]) = {
|
||||
NULL
|
||||
};
|
||||
|
||||
int highest_patch(void)
|
||||
{
|
||||
int i;
|
||||
int h = 0;
|
||||
|
||||
for (i = 0; included_patches[i] != 0; ++i) {
|
||||
if (included_patches[i] > h) {
|
||||
h = included_patches[i];
|
||||
}
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
/// Checks whether patch `n` has been included.
|
||||
///
|
||||
/// @param n The patch number.
|
||||
|
@ -8,7 +8,8 @@
|
||||
#ifndef NVIM_VIM_H
|
||||
# define NVIM_VIM_H
|
||||
|
||||
#define min(X, Y) (X < Y ? X : Y)
|
||||
#define MIN(X, Y) (X < Y ? X : Y)
|
||||
#define MAX(X, Y) (X > Y ? X : Y)
|
||||
|
||||
#include "nvim/types.h"
|
||||
#include "nvim/pos.h" // for linenr_T, MAXCOL, etc...
|
||||
|
@ -4,6 +4,7 @@ local clear, nvim, buffer, curbuf, curbuf_contents, window, curwin, eq, neq,
|
||||
ok, feed, rawfeed, insert, eval = helpers.clear, helpers.nvim, helpers.buffer, helpers.curbuf,
|
||||
helpers.curbuf_contents, helpers.window, helpers.curwin, helpers.eq,
|
||||
helpers.neq, helpers.ok, helpers.feed, helpers.rawfeed, helpers.insert, helpers.eval
|
||||
local wait = helpers.wait
|
||||
|
||||
-- check if str is visible at the beginning of some line
|
||||
local function is_visible(str)
|
||||
@ -55,6 +56,7 @@ describe('window_* functions', function()
|
||||
insert("epilogue")
|
||||
win = curwin()
|
||||
feed('gg')
|
||||
wait() -- let nvim process the 'gg' command
|
||||
|
||||
-- cursor position is at beginning
|
||||
eq({1, 0}, window('get_cursor', win))
|
||||
|
@ -229,11 +229,15 @@ local function curbuf(method, ...)
|
||||
return buffer(method, buf, ...)
|
||||
end
|
||||
|
||||
local function wait()
|
||||
session:request('vim_eval', '1')
|
||||
end
|
||||
|
||||
local function curbuf_contents()
|
||||
-- Before inspecting the buffer, execute 'vim_eval' to wait until all
|
||||
-- previously sent keys are processed(vim_eval is a deferred function, and
|
||||
-- only processed after all input)
|
||||
session:request('vim_eval', '1')
|
||||
wait()
|
||||
return table.concat(curbuf('get_line_slice', 0, -1, true, true), '\n')
|
||||
end
|
||||
|
||||
@ -284,5 +288,6 @@ return {
|
||||
curbuf = curbuf,
|
||||
curwin = curwin,
|
||||
curtab = curtab,
|
||||
curbuf_contents = curbuf_contents
|
||||
curbuf_contents = curbuf_contents,
|
||||
wait = wait
|
||||
}
|
||||
|
@ -1,23 +1,44 @@
|
||||
-- vim: set foldmethod=marker foldmarker=[[,]] :
|
||||
-- Tests for ":highlight".
|
||||
|
||||
local Screen = require('test.functional.ui.screen')
|
||||
local helpers = require('test.functional.helpers')
|
||||
local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert
|
||||
local execute, expect = helpers.execute, helpers.expect
|
||||
local wait = helpers.wait
|
||||
|
||||
describe(':highlight', function()
|
||||
setup(clear)
|
||||
|
||||
it('is working', function()
|
||||
local screen = Screen.new(35, 10)
|
||||
screen:attach()
|
||||
-- Basic test if ":highlight" doesn't crash
|
||||
execute('highlight')
|
||||
-- FIXME(tarruda): We need to be sure the prompt is displayed before
|
||||
-- continuing, or risk a race condition where some of the following input
|
||||
-- is discarded resulting in test failure
|
||||
screen:expect([[
|
||||
:highlight |
|
||||
SpecialKey xxx ctermfg=4 |
|
||||
guifg=Blue |
|
||||
EndOfBuffer xxx links to NonText|
|
||||
|
|
||||
NonText xxx ctermfg=12 |
|
||||
gui=bold |
|
||||
guifg=Blue |
|
||||
Directory xxx ctermfg=4 |
|
||||
-- More --^ |
|
||||
]])
|
||||
feed('q')
|
||||
wait() -- wait until we're back to normal
|
||||
execute('hi Search')
|
||||
|
||||
-- Test setting colors.
|
||||
-- Test clearing one color and all doesn't generate error or warning
|
||||
execute('hi NewGroup term=bold cterm=italic ctermfg=DarkBlue ctermbg=Grey gui= guifg=#00ff00 guibg=Cyan')
|
||||
execute('hi Group2 term= cterm=')
|
||||
execute('hi Group3 term=underline cterm=bold')
|
||||
execute('hi NewGroup cterm=italic ctermfg=DarkBlue ctermbg=Grey gui=NONE guifg=#00ff00 guibg=Cyan')
|
||||
execute('hi Group2 cterm=NONE')
|
||||
execute('hi Group3 cterm=bold')
|
||||
execute('redir! @a')
|
||||
execute('hi NewGroup')
|
||||
execute('hi Group2')
|
||||
@ -29,7 +50,7 @@ describe(':highlight', function()
|
||||
execute('hi Group2')
|
||||
execute('hi clear')
|
||||
execute('hi Group3')
|
||||
execute([[hi Crash term='asdf]])
|
||||
execute([[hi Crash cterm='asdf]])
|
||||
execute('redir END')
|
||||
|
||||
-- Filter ctermfg and ctermbg, the numbers depend on the terminal
|
||||
@ -48,11 +69,15 @@ describe(':highlight', function()
|
||||
expect([[
|
||||
|
||||
|
||||
NewGroup xxx term=bold cterm=italic ctermfg=2 ctermbg=3
|
||||
NewGroup xxx cterm=italic
|
||||
ctermfg=2
|
||||
ctermbg=3
|
||||
guifg=#00ff00
|
||||
guibg=Cyan
|
||||
|
||||
Group2 xxx cleared
|
||||
|
||||
Group3 xxx term=underline cterm=bold
|
||||
Group3 xxx cterm=bold
|
||||
|
||||
|
||||
NewGroup xxx cleared
|
||||
@ -65,6 +90,7 @@ describe(':highlight', function()
|
||||
|
||||
Group3 xxx cleared
|
||||
|
||||
E475: term='asdf]])
|
||||
E475: cterm='asdf]])
|
||||
screen:detach()
|
||||
end)
|
||||
end)
|
||||
|
@ -77,27 +77,7 @@ describe('system()', function()
|
||||
]])
|
||||
end)
|
||||
|
||||
it('`yes` and is directly interrupted with CTRL-C', function()
|
||||
feed(':call system("yes")<cr><c-c>')
|
||||
screen:expect([[
|
||||
^ |
|
||||
~ |
|
||||
~ |
|
||||
~ |
|
||||
~ |
|
||||
~ |
|
||||
~ |
|
||||
~ |
|
||||
~ |
|
||||
~ |
|
||||
~ |
|
||||
~ |
|
||||
~ |
|
||||
Type :quit<Enter> to exit Vim |
|
||||
]])
|
||||
end)
|
||||
|
||||
it('`yes` and is a little bit later interrupted with CTRL-C', function()
|
||||
it('`yes` and is interrupted with CTRL-C', function()
|
||||
feed(':call system("yes")<cr>')
|
||||
feed('<c-c>')
|
||||
screen:expect([[
|
||||
@ -247,26 +227,6 @@ describe('systemlist()', function()
|
||||
]])
|
||||
end)
|
||||
|
||||
it('`yes` and is directly interrupted with CTRL-C', function()
|
||||
feed(':call systemlist("yes | xargs")<cr><c-c>')
|
||||
screen:expect([[
|
||||
^ |
|
||||
~ |
|
||||
~ |
|
||||
~ |
|
||||
~ |
|
||||
~ |
|
||||
~ |
|
||||
~ |
|
||||
~ |
|
||||
~ |
|
||||
~ |
|
||||
~ |
|
||||
~ |
|
||||
Type :quit<Enter> to exit Vim |
|
||||
]])
|
||||
end)
|
||||
|
||||
it('`yes` and is a little bit later interrupted with CTRL-C', function()
|
||||
feed(':call systemlist("yes | xargs")<cr>')
|
||||
feed('<c-c>')
|
||||
|
@ -116,7 +116,11 @@ local debug_screen
|
||||
|
||||
local default_screen_timeout = 2500
|
||||
if os.getenv('VALGRIND') then
|
||||
default_screen_timeout = 7500
|
||||
default_screen_timeout = default_screen_timeout * 3
|
||||
end
|
||||
|
||||
if os.getenv('CI_TARGET') then
|
||||
default_screen_timeout = default_screen_timeout * 3
|
||||
end
|
||||
|
||||
local colors = request('vim_get_color_map')
|
||||
|
Loading…
Reference in New Issue
Block a user