Merge #7221 from justinmk/ev-focusgained

tui: schedule event instead of <FocusGained> pseudokey
This commit is contained in:
Justin M. Keyes 2017-09-06 07:25:01 +02:00 committed by GitHub
commit 51808a244e
19 changed files with 359 additions and 257 deletions

View File

@ -215,6 +215,7 @@ static void ui_set_option(UI *ui, String name, Object value, Error *error)
#undef UI_EXT_OPTION
}
/// Pushes data into UI.UIData, to be consumed later by remote_ui_flush().
static void push_call(UI *ui, char *name, Array args)
{
Array call = ARRAY_DICT_INIT;

View File

@ -255,12 +255,11 @@ free_vim_args:
return rv;
}
/// Execute lua code. Parameters might be passed, they are available inside
/// the chunk as `...`. The chunk can return a value.
/// Execute lua code. Parameters (if any) are available as `...` inside the
/// chunk. The chunk can return a value.
///
/// To evaluate an expression, it must be prefixed with "return ". For
/// instance, to call a lua function with arguments sent in and get its
/// return value back, use the code "return my_function(...)".
/// Only statements are executed. To evaluate an expression, prefix it
/// with `return`: return my_function(...)
///
/// @param code lua code to execute
/// @param args Arguments to the code
@ -423,29 +422,18 @@ void nvim_del_var(String name, Error *err)
dict_set_var(&globvardict, name, NIL, true, false, err);
}
/// Sets a global variable
///
/// @deprecated
///
/// @param name Variable name
/// @param value Variable value
/// @param[out] err Error details, if any
/// @see nvim_set_var
/// @return Old value or nil if there was no previous value.
///
/// @warning It may return nil if there was no previous value
/// or if previous value was `v:null`.
/// @warning May return nil if there was no previous value
/// OR if previous value was `v:null`.
Object vim_set_var(String name, Object value, Error *err)
{
return dict_set_var(&globvardict, name, value, false, true, err);
}
/// Removes a global variable
///
/// @deprecated
///
/// @param name Variable name
/// @param[out] err Error details, if any
/// @return Old value
/// @see nvim_del_var
Object vim_del_var(String name, Error *err)
{
return dict_set_var(&globvardict, name, NIL, true, true, err);

41
src/nvim/aucmd.c Normal file
View File

@ -0,0 +1,41 @@
// This is an open source non-commercial project. Dear PVS-Studio, please check
// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#include "nvim/os/os.h"
#include "nvim/fileio.h"
#include "nvim/vim.h"
#include "nvim/main.h"
#include "nvim/ui.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "aucmd.c.generated.h"
#endif
static void focusgained_event(void **argv)
{
bool *gainedp = argv[0];
do_autocmd_focusgained(*gainedp);
xfree(gainedp);
}
void aucmd_schedule_focusgained(bool gained)
{
bool *gainedp = xmalloc(sizeof(*gainedp));
*gainedp = gained;
loop_schedule_deferred(&main_loop,
event_create(focusgained_event, 1, gainedp));
}
static void do_autocmd_focusgained(bool gained)
FUNC_ATTR_NONNULL_ALL
{
static bool recursive = false;
if (recursive) {
return; // disallow recursion
}
recursive = true;
apply_autocmds((gained ? EVENT_FOCUSGAINED : EVENT_FOCUSLOST),
NULL, NULL, false, curbuf);
recursive = false;
}

9
src/nvim/aucmd.h Normal file
View File

@ -0,0 +1,9 @@
#ifndef NVIM_AUCMD_H
#define NVIM_AUCMD_H
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "aucmd.h.generated.h"
#endif
#endif // NVIM_AUCMD_H

View File

@ -974,14 +974,6 @@ static int insert_handle_key(InsertState *s)
multiqueue_process_events(main_loop.events);
break;
case K_FOCUSGAINED: // Neovim has been given focus
apply_autocmds(EVENT_FOCUSGAINED, NULL, NULL, false, curbuf);
break;
case K_FOCUSLOST: // Neovim has lost focus
apply_autocmds(EVENT_FOCUSLOST, NULL, NULL, false, curbuf);
break;
case K_HOME: // <Home>
case K_KHOME:
case K_S_HOME:
@ -3167,8 +3159,7 @@ static bool ins_compl_prep(int c)
/* Ignore end of Select mode mapping and mouse scroll buttons. */
if (c == K_SELECT || c == K_MOUSEDOWN || c == K_MOUSEUP
|| c == K_MOUSELEFT || c == K_MOUSERIGHT || c == K_EVENT
|| c == K_FOCUSGAINED || c == K_FOCUSLOST) {
|| c == K_MOUSELEFT || c == K_MOUSERIGHT || c == K_EVENT) {
return retval;
}

View File

@ -59,7 +59,14 @@ void loop_poll_events(Loop *loop, int ms)
multiqueue_process_events(loop->fast_events);
}
// Schedule an event from another thread
/// Schedules an event from another thread.
///
/// @note Event is queued into `fast_events`, which is processed outside of the
/// primary `events` queue by loop_poll_events(). For `main_loop`, that
/// means `fast_events` is NOT processed in an "editor mode"
/// (VimState.execute), so redraw and other side-effects are likely to be
/// skipped.
/// @see loop_schedule_deferred
void loop_schedule(Loop *loop, Event event)
{
uv_mutex_lock(&loop->mutex);
@ -68,6 +75,24 @@ void loop_schedule(Loop *loop, Event event)
uv_mutex_unlock(&loop->mutex);
}
/// Schedules an event from another thread. Unlike loop_schedule(), the event
/// is forwarded to `Loop.events`, instead of being processed immediately.
///
/// @see loop_schedule
void loop_schedule_deferred(Loop *loop, Event event)
{
Event *eventp = xmalloc(sizeof(*eventp));
*eventp = event;
loop_schedule(loop, event_create(loop_deferred_event, 2, loop, eventp));
}
static void loop_deferred_event(void **argv)
{
Loop *loop = argv[0];
Event *eventp = argv[1];
multiqueue_put_event(loop->events, *eventp);
xfree(eventp);
}
void loop_on_put(MultiQueue *queue, void *data)
{
Loop *loop = data;

View File

@ -16,10 +16,28 @@ KLIST_INIT(WatcherPtr, WatcherPtr, _noop)
typedef struct loop {
uv_loop_t uv;
MultiQueue *events, *fast_events, *thread_events;
MultiQueue *events;
MultiQueue *thread_events;
// Immediate events:
// "Events that should be processed after exiting uv_run() (to avoid
// recursion), but before returning from loop_poll_events()."
// 502aee690c980fcb3cfcb3f211dcfad06103db46
// Practical consequence: these events are processed by
// state_enter()..os_inchar()
// whereas "regular" (main_loop.events) events are processed by
// state_enter()..VimState.execute()
// But state_enter()..os_inchar() can be "too early" if you want the event
// to trigger UI updates and other user-activity-related side-effects.
MultiQueue *fast_events;
// used by process/job-control subsystem
klist_t(WatcherPtr) *children;
uv_signal_t children_watcher;
uv_timer_t children_kill_timer, poll_timer;
uv_timer_t children_kill_timer;
// generic timer, used by loop_poll_events()
uv_timer_t poll_timer;
size_t children_stop_requests;
uv_async_t async;
uv_mutex_t mutex;

View File

@ -1620,14 +1620,6 @@ static int command_line_handle_key(CommandLineState *s)
}
return command_line_not_changed(s);
case K_FOCUSGAINED: // Neovim has been given focus
apply_autocmds(EVENT_FOCUSGAINED, NULL, NULL, false, curbuf);
return command_line_not_changed(s);
case K_FOCUSLOST: // Neovim has lost focus
apply_autocmds(EVENT_FOCUSLOST, NULL, NULL, false, curbuf);
return command_line_not_changed(s);
default:
// Normal character with no special meaning. Just set mod_mask
// to 0x0 so that typing Shift-Space in the GUI doesn't enter

View File

@ -140,155 +140,153 @@ static char_u modifier_keys_table[] =
};
static struct key_name_entry {
int key; /* Special key code or ascii value */
char_u *name; /* Name of key */
int key; // Special key code or ascii value
char *name; // Name of key
} key_names_table[] =
{
{' ', (char_u *)"Space"},
{TAB, (char_u *)"Tab"},
{K_TAB, (char_u *)"Tab"},
{NL, (char_u *)"NL"},
{NL, (char_u *)"NewLine"}, /* Alternative name */
{NL, (char_u *)"LineFeed"}, /* Alternative name */
{NL, (char_u *)"LF"}, /* Alternative name */
{CAR, (char_u *)"CR"},
{CAR, (char_u *)"Return"}, /* Alternative name */
{CAR, (char_u *)"Enter"}, /* Alternative name */
{K_BS, (char_u *)"BS"},
{K_BS, (char_u *)"BackSpace"}, /* Alternative name */
{ESC, (char_u *)"Esc"},
{CSI, (char_u *)"CSI"},
{K_CSI, (char_u *)"xCSI"},
{'|', (char_u *)"Bar"},
{'\\', (char_u *)"Bslash"},
{K_DEL, (char_u *)"Del"},
{K_DEL, (char_u *)"Delete"}, /* Alternative name */
{K_KDEL, (char_u *)"kDel"},
{K_UP, (char_u *)"Up"},
{K_DOWN, (char_u *)"Down"},
{K_LEFT, (char_u *)"Left"},
{K_RIGHT, (char_u *)"Right"},
{K_XUP, (char_u *)"xUp"},
{K_XDOWN, (char_u *)"xDown"},
{K_XLEFT, (char_u *)"xLeft"},
{K_XRIGHT, (char_u *)"xRight"},
{ ' ', "Space" },
{ TAB, "Tab" },
{ K_TAB, "Tab" },
{ NL, "NL" },
{ NL, "NewLine" }, // Alternative name
{ NL, "LineFeed" }, // Alternative name
{ NL, "LF" }, // Alternative name
{ CAR, "CR" },
{ CAR, "Return" }, // Alternative name
{ CAR, "Enter" }, // Alternative name
{ K_BS, "BS" },
{ K_BS, "BackSpace" }, // Alternative name
{ ESC, "Esc" },
{ CSI, "CSI" },
{ K_CSI, "xCSI" },
{ '|', "Bar" },
{ '\\', "Bslash" },
{ K_DEL, "Del" },
{ K_DEL, "Delete" }, // Alternative name
{ K_KDEL, "kDel" },
{ K_UP, "Up" },
{ K_DOWN, "Down" },
{ K_LEFT, "Left" },
{ K_RIGHT, "Right" },
{ K_XUP, "xUp" },
{ K_XDOWN, "xDown" },
{ K_XLEFT, "xLeft" },
{ K_XRIGHT, "xRight" },
{K_F1, (char_u *)"F1"},
{K_F2, (char_u *)"F2"},
{K_F3, (char_u *)"F3"},
{K_F4, (char_u *)"F4"},
{K_F5, (char_u *)"F5"},
{K_F6, (char_u *)"F6"},
{K_F7, (char_u *)"F7"},
{K_F8, (char_u *)"F8"},
{K_F9, (char_u *)"F9"},
{K_F10, (char_u *)"F10"},
{ K_F1, "F1" },
{ K_F2, "F2" },
{ K_F3, "F3" },
{ K_F4, "F4" },
{ K_F5, "F5" },
{ K_F6, "F6" },
{ K_F7, "F7" },
{ K_F8, "F8" },
{ K_F9, "F9" },
{ K_F10, "F10" },
{K_F11, (char_u *)"F11"},
{K_F12, (char_u *)"F12"},
{K_F13, (char_u *)"F13"},
{K_F14, (char_u *)"F14"},
{K_F15, (char_u *)"F15"},
{K_F16, (char_u *)"F16"},
{K_F17, (char_u *)"F17"},
{K_F18, (char_u *)"F18"},
{K_F19, (char_u *)"F19"},
{K_F20, (char_u *)"F20"},
{ K_F11, "F11" },
{ K_F12, "F12" },
{ K_F13, "F13" },
{ K_F14, "F14" },
{ K_F15, "F15" },
{ K_F16, "F16" },
{ K_F17, "F17" },
{ K_F18, "F18" },
{ K_F19, "F19" },
{ K_F20, "F20" },
{K_F21, (char_u *)"F21"},
{K_F22, (char_u *)"F22"},
{K_F23, (char_u *)"F23"},
{K_F24, (char_u *)"F24"},
{K_F25, (char_u *)"F25"},
{K_F26, (char_u *)"F26"},
{K_F27, (char_u *)"F27"},
{K_F28, (char_u *)"F28"},
{K_F29, (char_u *)"F29"},
{K_F30, (char_u *)"F30"},
{ K_F21, "F21" },
{ K_F22, "F22" },
{ K_F23, "F23" },
{ K_F24, "F24" },
{ K_F25, "F25" },
{ K_F26, "F26" },
{ K_F27, "F27" },
{ K_F28, "F28" },
{ K_F29, "F29" },
{ K_F30, "F30" },
{K_F31, (char_u *)"F31"},
{K_F32, (char_u *)"F32"},
{K_F33, (char_u *)"F33"},
{K_F34, (char_u *)"F34"},
{K_F35, (char_u *)"F35"},
{K_F36, (char_u *)"F36"},
{K_F37, (char_u *)"F37"},
{ K_F31, "F31" },
{ K_F32, "F32" },
{ K_F33, "F33" },
{ K_F34, "F34" },
{ K_F35, "F35" },
{ K_F36, "F36" },
{ K_F37, "F37" },
{K_XF1, (char_u *)"xF1"},
{K_XF2, (char_u *)"xF2"},
{K_XF3, (char_u *)"xF3"},
{K_XF4, (char_u *)"xF4"},
{ K_XF1, "xF1" },
{ K_XF2, "xF2" },
{ K_XF3, "xF3" },
{ K_XF4, "xF4" },
{K_HELP, (char_u *)"Help"},
{K_UNDO, (char_u *)"Undo"},
{K_INS, (char_u *)"Insert"},
{K_INS, (char_u *)"Ins"}, /* Alternative name */
{K_KINS, (char_u *)"kInsert"},
{K_HOME, (char_u *)"Home"},
{K_KHOME, (char_u *)"kHome"},
{K_XHOME, (char_u *)"xHome"},
{K_ZHOME, (char_u *)"zHome"},
{K_END, (char_u *)"End"},
{K_KEND, (char_u *)"kEnd"},
{K_XEND, (char_u *)"xEnd"},
{K_ZEND, (char_u *)"zEnd"},
{K_PAGEUP, (char_u *)"PageUp"},
{K_PAGEDOWN, (char_u *)"PageDown"},
{K_KPAGEUP, (char_u *)"kPageUp"},
{K_KPAGEDOWN, (char_u *)"kPageDown"},
{ K_HELP, "Help" },
{ K_UNDO, "Undo" },
{ K_INS, "Insert" },
{ K_INS, "Ins" }, // Alternative name
{ K_KINS, "kInsert" },
{ K_HOME, "Home" },
{ K_KHOME, "kHome" },
{ K_XHOME, "xHome" },
{ K_ZHOME, "zHome" },
{ K_END, "End" },
{ K_KEND, "kEnd" },
{ K_XEND, "xEnd" },
{ K_ZEND, "zEnd" },
{ K_PAGEUP, "PageUp" },
{ K_PAGEDOWN, "PageDown" },
{ K_KPAGEUP, "kPageUp" },
{ K_KPAGEDOWN, "kPageDown" },
{K_KPLUS, (char_u *)"kPlus"},
{K_KMINUS, (char_u *)"kMinus"},
{K_KDIVIDE, (char_u *)"kDivide"},
{K_KMULTIPLY, (char_u *)"kMultiply"},
{K_KENTER, (char_u *)"kEnter"},
{K_KPOINT, (char_u *)"kPoint"},
{ K_KPLUS, "kPlus" },
{ K_KMINUS, "kMinus" },
{ K_KDIVIDE, "kDivide" },
{ K_KMULTIPLY, "kMultiply" },
{ K_KENTER, "kEnter" },
{ K_KPOINT, "kPoint" },
{K_K0, (char_u *)"k0"},
{K_K1, (char_u *)"k1"},
{K_K2, (char_u *)"k2"},
{K_K3, (char_u *)"k3"},
{K_K4, (char_u *)"k4"},
{K_K5, (char_u *)"k5"},
{K_K6, (char_u *)"k6"},
{K_K7, (char_u *)"k7"},
{K_K8, (char_u *)"k8"},
{K_K9, (char_u *)"k9"},
{ K_K0, "k0" },
{ K_K1, "k1" },
{ K_K2, "k2" },
{ K_K3, "k3" },
{ K_K4, "k4" },
{ K_K5, "k5" },
{ K_K6, "k6" },
{ K_K7, "k7" },
{ K_K8, "k8" },
{ K_K9, "k9" },
{'<', (char_u *)"lt"},
{ '<', "lt" },
{K_MOUSE, (char_u *)"Mouse"},
{K_LEFTMOUSE, (char_u *)"LeftMouse"},
{K_LEFTMOUSE_NM, (char_u *)"LeftMouseNM"},
{K_LEFTDRAG, (char_u *)"LeftDrag"},
{K_LEFTRELEASE, (char_u *)"LeftRelease"},
{K_LEFTRELEASE_NM, (char_u *)"LeftReleaseNM"},
{K_MIDDLEMOUSE, (char_u *)"MiddleMouse"},
{K_MIDDLEDRAG, (char_u *)"MiddleDrag"},
{K_MIDDLERELEASE, (char_u *)"MiddleRelease"},
{K_RIGHTMOUSE, (char_u *)"RightMouse"},
{K_RIGHTDRAG, (char_u *)"RightDrag"},
{K_RIGHTRELEASE, (char_u *)"RightRelease"},
{K_MOUSEDOWN, (char_u *)"ScrollWheelUp"},
{K_MOUSEUP, (char_u *)"ScrollWheelDown"},
{K_MOUSELEFT, (char_u *)"ScrollWheelRight"},
{K_MOUSERIGHT, (char_u *)"ScrollWheelLeft"},
{K_MOUSEDOWN, (char_u *)"MouseDown"}, /* OBSOLETE: Use */
{K_MOUSEUP, (char_u *)"MouseUp"}, /* ScrollWheelXXX instead */
{K_X1MOUSE, (char_u *)"X1Mouse"},
{K_X1DRAG, (char_u *)"X1Drag"},
{K_X1RELEASE, (char_u *)"X1Release"},
{K_X2MOUSE, (char_u *)"X2Mouse"},
{K_X2DRAG, (char_u *)"X2Drag"},
{K_X2RELEASE, (char_u *)"X2Release"},
{K_DROP, (char_u *)"Drop"},
{K_ZERO, (char_u *)"Nul"},
{K_SNR, (char_u *)"SNR"},
{K_PLUG, (char_u *)"Plug"},
{K_PASTE, (char_u *)"Paste"},
{K_FOCUSGAINED, (char_u *)"FocusGained"},
{K_FOCUSLOST, (char_u *)"FocusLost"},
{0, NULL}
{ K_MOUSE, "Mouse" },
{ K_LEFTMOUSE, "LeftMouse" },
{ K_LEFTMOUSE_NM, "LeftMouseNM" },
{ K_LEFTDRAG, "LeftDrag" },
{ K_LEFTRELEASE, "LeftRelease" },
{ K_LEFTRELEASE_NM, "LeftReleaseNM" },
{ K_MIDDLEMOUSE, "MiddleMouse" },
{ K_MIDDLEDRAG, "MiddleDrag" },
{ K_MIDDLERELEASE, "MiddleRelease" },
{ K_RIGHTMOUSE, "RightMouse" },
{ K_RIGHTDRAG, "RightDrag" },
{ K_RIGHTRELEASE, "RightRelease" },
{ K_MOUSEDOWN, "ScrollWheelUp" },
{ K_MOUSEUP, "ScrollWheelDown" },
{ K_MOUSELEFT, "ScrollWheelRight" },
{ K_MOUSERIGHT, "ScrollWheelLeft" },
{ K_MOUSEDOWN, "MouseDown" }, // OBSOLETE: Use
{ K_MOUSEUP, "MouseUp" }, // ScrollWheelXXX instead
{ K_X1MOUSE, "X1Mouse" },
{ K_X1DRAG, "X1Drag" },
{ K_X1RELEASE, "X1Release" },
{ K_X2MOUSE, "X2Mouse" },
{ K_X2DRAG, "X2Drag" },
{ K_X2RELEASE, "X2Release" },
{ K_DROP, "Drop" },
{ K_ZERO, "Nul" },
{ K_SNR, "SNR" },
{ K_PLUG, "Plug" },
{ K_PASTE, "Paste" },
{ 0, NULL }
};
static struct mousetable {
@ -721,7 +719,7 @@ int find_special_key_in_table(int c)
*/
int get_special_key_code(const char_u *name)
{
char_u *table_name;
char *table_name;
int i, j;
for (i = 0; key_names_table[i].name != NULL; i++) {

View File

@ -428,8 +428,6 @@ enum key_extra {
#define K_CMDWIN TERMCAP2KEY(KS_EXTRA, KE_CMDWIN)
#define K_DROP TERMCAP2KEY(KS_EXTRA, KE_DROP)
#define K_FOCUSGAINED TERMCAP2KEY(KS_EXTRA, KE_FOCUSGAINED)
#define K_FOCUSLOST TERMCAP2KEY(KS_EXTRA, KE_FOCUSLOST)
#define K_EVENT TERMCAP2KEY(KS_EXTRA, KE_EVENT)
#define K_PASTE TERMCAP2KEY(KS_EXTRA, KE_PASTE)

View File

@ -95,8 +95,12 @@ void log_unlock(void)
uv_mutex_unlock(&mutex);
}
bool do_log(int log_level, const char *func_name, int line_num, bool eol,
const char* fmt, ...) FUNC_ATTR_UNUSED
/// @param context description of a shared context or subsystem
/// @param func_name function name, or NULL
/// @param line_num source line number, or -1
bool do_log(int log_level, const char *context, const char *func_name,
int line_num, bool eol, const char *fmt, ...)
FUNC_ATTR_UNUSED
{
if (log_level < MIN_LOG_LEVEL) {
return false;
@ -112,8 +116,8 @@ bool do_log(int log_level, const char *func_name, int line_num, bool eol,
va_list args;
va_start(args, fmt);
ret = v_do_log_to_file(log_file, log_level, func_name, line_num, eol,
fmt, args);
ret = v_do_log_to_file(log_file, log_level, context, func_name, line_num,
eol, fmt, args);
va_end(args);
if (log_file != stderr && log_file != stdout) {
@ -151,7 +155,7 @@ FILE *open_log_file(void)
static bool opening_log_file = false;
// check if it's a recursive call
if (opening_log_file) {
do_log_to_file(stderr, ERROR_LOG_LEVEL, __func__, __LINE__, true,
do_log_to_file(stderr, ERROR_LOG_LEVEL, NULL, __func__, __LINE__, true,
"Cannot LOG() recursively.");
return stderr;
}
@ -171,7 +175,7 @@ FILE *open_log_file(void)
// - LOG() is called before early_init()
// - Directory does not exist
// - File is not writable
do_log_to_file(stderr, ERROR_LOG_LEVEL, __func__, __LINE__, true,
do_log_to_file(stderr, ERROR_LOG_LEVEL, NULL, __func__, __LINE__, true,
"Logging to stderr, failed to open $" LOG_FILE_ENV ": %s",
log_file_path);
return stderr;
@ -201,7 +205,7 @@ void log_callstack_to_file(FILE *log_file, const char *const func_name,
// Now we have a command string like:
// addr2line -e /path/to/exe -f -p 0x123 0x456 ...
do_log_to_file(log_file, DEBUG_LOG_LEVEL, func_name, line_num, true,
do_log_to_file(log_file, DEBUG_LOG_LEVEL, NULL, func_name, line_num, true,
"trace:");
FILE *fp = popen(cmdbuf, "r");
char linebuf[IOSIZE];
@ -230,22 +234,23 @@ end:
}
#endif
static bool do_log_to_file(FILE *log_file, int log_level,
static bool do_log_to_file(FILE *log_file, int log_level, const char *context,
const char *func_name, int line_num, bool eol,
const char* fmt, ...)
{
va_list args;
va_start(args, fmt);
bool ret = v_do_log_to_file(log_file, log_level, func_name, line_num, eol,
fmt, args);
bool ret = v_do_log_to_file(log_file, log_level, context, func_name,
line_num, eol, fmt, args);
va_end(args);
return ret;
}
static bool v_do_log_to_file(FILE *log_file, int log_level,
const char *func_name, int line_num, bool eol,
const char* fmt, va_list args)
const char *context, const char *func_name,
int line_num, bool eol, const char *fmt,
va_list args)
{
static const char *log_levels[] = {
[DEBUG_LOG_LEVEL] = "DEBUG",
@ -268,8 +273,15 @@ static bool v_do_log_to_file(FILE *log_file, int log_level,
// print the log message prefixed by the current timestamp and pid
int64_t pid = os_get_pid();
if (fprintf(log_file, "%s %s %" PRId64 "/%s:%d: ", date_time,
log_levels[log_level], pid, func_name, line_num) < 0) {
int rv = (line_num == -1 || func_name == NULL)
? fprintf(log_file, "%s %s %" PRId64 " %s", date_time,
log_levels[log_level], pid,
(context == NULL ? "?:" : context))
: fprintf(log_file, "%s %s %" PRId64 " %s%s:%d: ", date_time,
log_levels[log_level], pid,
(context == NULL ? "" : context),
func_name, line_num);
if (rv < 0) {
return false;
}
if (vfprintf(log_file, fmt, args) < 0) {

View File

@ -22,42 +22,42 @@
# define MIN_LOG_LEVEL INFO_LOG_LEVEL
#endif
#define LOG(level, ...) do_log((level), __func__, __LINE__, true, \
#define LOG(level, ...) do_log((level), NULL, __func__, __LINE__, true, \
__VA_ARGS__)
#if MIN_LOG_LEVEL <= DEBUG_LOG_LEVEL
# undef DLOG
# undef DLOGN
# define DLOG(...) do_log(DEBUG_LOG_LEVEL, __func__, __LINE__, true, \
# define DLOG(...) do_log(DEBUG_LOG_LEVEL, NULL, __func__, __LINE__, true, \
__VA_ARGS__)
# define DLOGN(...) do_log(DEBUG_LOG_LEVEL, __func__, __LINE__, false, \
# define DLOGN(...) do_log(DEBUG_LOG_LEVEL, NULL, __func__, __LINE__, false, \
__VA_ARGS__)
#endif
#if MIN_LOG_LEVEL <= INFO_LOG_LEVEL
# undef ILOG
# undef ILOGN
# define ILOG(...) do_log(INFO_LOG_LEVEL, __func__, __LINE__, true, \
# define ILOG(...) do_log(INFO_LOG_LEVEL, NULL, __func__, __LINE__, true, \
__VA_ARGS__)
# define ILOGN(...) do_log(INFO_LOG_LEVEL, __func__, __LINE__, false, \
# define ILOGN(...) do_log(INFO_LOG_LEVEL, NULL, __func__, __LINE__, false, \
__VA_ARGS__)
#endif
#if MIN_LOG_LEVEL <= WARN_LOG_LEVEL
# undef WLOG
# undef WLOGN
# define WLOG(...) do_log(WARN_LOG_LEVEL, __func__, __LINE__, true, \
# define WLOG(...) do_log(WARN_LOG_LEVEL, NULL, __func__, __LINE__, true, \
__VA_ARGS__)
# define WLOGN(...) do_log(WARN_LOG_LEVEL, __func__, __LINE__, false, \
# define WLOGN(...) do_log(WARN_LOG_LEVEL, NULL, __func__, __LINE__, false, \
__VA_ARGS__)
#endif
#if MIN_LOG_LEVEL <= ERROR_LOG_LEVEL
# undef ELOG
# undef ELOGN
# define ELOG(...) do_log(ERROR_LOG_LEVEL, __func__, __LINE__, true, \
# define ELOG(...) do_log(ERROR_LOG_LEVEL, NULL, __func__, __LINE__, true, \
__VA_ARGS__)
# define ELOGN(...) do_log(ERROR_LOG_LEVEL, __func__, __LINE__, false, \
# define ELOGN(...) do_log(ERROR_LOG_LEVEL, NULL, __func__, __LINE__, false, \
__VA_ARGS__)
#endif

View File

@ -188,12 +188,11 @@ uint64_t channel_connect(bool tcp, const char *address, int timeout,
return channel->id;
}
/// Sends event/arguments to channel
/// Publishes an event to a channel.
///
/// @param id The channel id. If 0, the event will be sent to all
/// channels that have subscribed to the event type
/// @param name The event name, an arbitrary string
/// @param args Array with event arguments
/// @param id Channel id. 0 means "broadcast to all subscribed channels"
/// @param name Event name (application-defined)
/// @param args Array of event arguments
/// @return True if the event was sent successfully, false otherwise.
bool channel_send_event(uint64_t id, const char *name, Array args)
{
@ -215,7 +214,6 @@ bool channel_send_event(uint64_t id, const char *name, Array args)
send_event(channel, name, args);
}
} else {
// TODO(tarruda): Implement event broadcasting in vimscript
broadcast_event(name, args);
}

View File

@ -345,8 +345,6 @@ static const struct nv_cmd {
{ K_F8, farsi_f8, 0, 0 },
{ K_F9, farsi_f9, 0, 0 },
{ K_EVENT, nv_event, NV_KEEPREG, 0 },
{ K_FOCUSGAINED, nv_focusgained, NV_KEEPREG, 0 },
{ K_FOCUSLOST, nv_focuslost, NV_KEEPREG, 0 },
};
/* Number of commands in nv_cmds[]. */
@ -7961,18 +7959,6 @@ static void nv_event(cmdarg_T *cap)
finish_op = false;
}
/// Trigger FocusGained event.
static void nv_focusgained(cmdarg_T *cap)
{
apply_autocmds(EVENT_FOCUSGAINED, NULL, NULL, false, curbuf);
}
/// Trigger FocusLost event.
static void nv_focuslost(cmdarg_T *cap)
{
apply_autocmds(EVENT_FOCUSLOST, NULL, NULL, false, curbuf);
}
/*
* Return TRUE when 'mousemodel' is set to "popup" or "popup_setpos".
*/

View File

@ -26,10 +26,11 @@ void state_enter(VimState *s)
int check_result = s->check ? s->check(s) : 1;
if (!check_result) {
break;
break; // Terminate this state.
} else if (check_result == -1) {
continue;
continue; // check() again.
}
// Execute this state.
int key;
@ -48,11 +49,13 @@ getkey:
ui_flush();
// Call `os_inchar` directly to block for events or user input without
// consuming anything from `input_buffer`(os/input.c) or calling the
// mapping engine. If an event was put into the queue, we send K_EVENT
// directly.
// mapping engine.
(void)os_inchar(NULL, 0, -1, 0);
input_disable_events();
key = !multiqueue_empty(main_loop.events) ? K_EVENT : safe_vgetc();
// If an event was put into the queue, we send K_EVENT directly.
key = !multiqueue_empty(main_loop.events)
? K_EVENT
: safe_vgetc();
}
if (key == K_EVENT) {

View File

@ -432,14 +432,6 @@ static int terminal_execute(VimState *state, int key)
TerminalState *s = (TerminalState *)state;
switch (key) {
case K_FOCUSGAINED: // nvim has been given focus
apply_autocmds(EVENT_FOCUSGAINED, NULL, NULL, false, curbuf);
break;
case K_FOCUSLOST: // nvim has lost focus
apply_autocmds(EVENT_FOCUSLOST, NULL, NULL, false, curbuf);
break;
// Temporary fix until paste events gets implemented
case K_PASTE:
break;

View File

@ -8,6 +8,7 @@
#include "nvim/api/private/helpers.h"
#include "nvim/ascii.h"
#include "nvim/main.h"
#include "nvim/aucmd.h"
#include "nvim/os/os.h"
#include "nvim/os/input.h"
#include "nvim/event/rstream.h"
@ -280,9 +281,9 @@ static void timer_cb(TimeWatcher *watcher, void *data)
/// Handle focus events.
///
/// If the upcoming sequence of bytes in the input stream matches either the
/// escape code for focus gained `<ESC>[I` or focus lost `<ESC>[O` then consume
/// that sequence and push the appropriate event into the input queue
/// If the upcoming sequence of bytes in the input stream matches the termcode
/// for "focus gained" or "focus lost", consume that sequence and schedule an
/// event on the main loop.
///
/// @param input the input stream
/// @return true iff handle_focus_event consumed some input
@ -294,11 +295,7 @@ static bool handle_focus_event(TermInput *input)
// Advance past the sequence
bool focus_gained = *rbuffer_get(input->read_stream.buffer, 2) == 'I';
rbuffer_consumed(input->read_stream.buffer, 3);
if (focus_gained) {
enqueue_input(input, FOCUSGAINED_KEY, sizeof(FOCUSGAINED_KEY) - 1);
} else {
enqueue_input(input, FOCUSLOST_KEY, sizeof(FOCUSLOST_KEY) - 1);
}
aucmd_schedule_focusgained(focus_gained);
return true;
}
return false;

View File

@ -71,10 +71,10 @@ static char uilog_last_event[1024] = { 0 };
uilog_seen++; \
} else { \
if (uilog_seen > 0) { \
do_log(DEBUG_LOG_LEVEL, "ui", 0, true, \
do_log(DEBUG_LOG_LEVEL, "UI: ", NULL, -1, true, \
"%s (+%zu times...)", uilog_last_event, uilog_seen); \
} \
DLOG("ui: " STR(funname)); \
do_log(DEBUG_LOG_LEVEL, "UI: ", NULL, -1, true, STR(funname)); \
uilog_seen = 0; \
xstrlcpy(uilog_last_event, STR(funname), sizeof(uilog_last_event)); \
} \

View File

@ -1,5 +1,6 @@
-- Some sanity checks for the TUI using the builtin terminal emulator
-- as a simple way to send keys and assert screen state.
-- TUI acceptance tests.
-- Uses :terminal as a way to send keys and assert screen state.
local global_helpers = require('test.helpers')
local helpers = require('test.functional.helpers')(after_each)
local thelpers = require('test.functional.terminal.helpers')
local feed_data = thelpers.feed_data
@ -194,7 +195,7 @@ describe('tui with non-tty file descriptors', function()
end)
end)
describe('tui focus event handling', function()
describe('tui FocusGained/FocusLost', function()
local screen
before_each(function()
@ -206,7 +207,8 @@ describe('tui focus event handling', function()
feed_data("\034\016") -- CTRL-\ CTRL-N
end)
it('can handle focus events in normal mode', function()
it('in normal-mode', function()
retry(2, 3 * screen.timeout, function()
feed_data('\027[I')
screen:expect([[
{1: } |
@ -228,11 +230,13 @@ describe('tui focus event handling', function()
lost |
{3:-- TERMINAL --} |
]])
end)
end)
it('can handle focus events in insert mode', function()
it('in insert-mode', function()
feed_command('set noshowmode')
feed_data('i')
retry(2, 3 * screen.timeout, function()
feed_data('\027[I')
screen:expect([[
{1: } |
@ -253,9 +257,12 @@ describe('tui focus event handling', function()
lost |
{3:-- TERMINAL --} |
]])
end)
end)
it('can handle focus events in cmdline mode', function()
-- During cmdline-mode we ignore :echo invoked by timers/events.
-- See commit: 5cc87d4dabd02167117be7a978b5c8faaa975419.
it('in cmdline-mode does NOT :echo', function()
feed_data(':')
feed_data('\027[I')
screen:expect([[
@ -264,7 +271,7 @@ describe('tui focus event handling', function()
{4:~ }|
{4:~ }|
{5:[No Name] }|
g{1:a}ined |
:{1: } |
{3:-- TERMINAL --} |
]])
feed_data('\027[O')
@ -274,17 +281,46 @@ describe('tui focus event handling', function()
{4:~ }|
{4:~ }|
{5:[No Name] }|
l{1:o}st |
:{1: } |
{3:-- TERMINAL --} |
]])
end)
it('can handle focus events in terminal mode', function()
it('in cmdline-mode', function()
-- Set up autocmds that modify the buffer, instead of just calling :echo.
-- This is how we can test handling of focus gained/lost during cmdline-mode.
-- See commit: 5cc87d4dabd02167117be7a978b5c8faaa975419.
feed_data(":autocmd!\n")
feed_data(":autocmd FocusLost * call append(line('$'), 'lost')\n")
feed_data(":autocmd FocusGained * call append(line('$'), 'gained')\n")
-- Enter cmdline-mode.
feed_data(':')
screen:sleep(1)
-- Send focus lost/gained termcodes.
feed_data('\027[O')
feed_data('\027[I')
screen:sleep(1)
-- Exit cmdline-mode. Redraws from timers/events are blocked during
-- cmdline-mode, so the buffer won't be updated until we exit cmdline-mode.
feed_data('\n')
screen:expect([[
{1: } |
lost |
gained |
{4:~ }|
{5:[No Name] [+] }|
: |
{3:-- TERMINAL --} |
]])
end)
it('in terminal-mode', function()
feed_data(':set shell='..nvim_dir..'/shell-test\n')
feed_data(':set noshowmode laststatus=0\n')
retry(2, 3 * screen.timeout, function()
feed_data(':terminal\n')
screen:sleep(1)
feed_data('\027[I')
screen:expect([[
{1:r}eady $ |
@ -311,13 +347,30 @@ describe('tui focus event handling', function()
feed_data(':bwipeout!\n')
end)
end)
it('in press-enter prompt', function()
feed_data(":echom 'msg1'|echom 'msg2'|echom 'msg3'|echom 'msg4'|echom 'msg5'\n")
-- Execute :messages to provoke the press-enter prompt.
feed_data(":messages\n")
feed_data('\027[I')
feed_data('\027[I')
screen:expect([[
msg1 |
msg2 |
msg3 |
msg4 |
msg5 |
{10:Press ENTER or type command to continue}{1: } |
{3:-- TERMINAL --} |
]])
end)
end)
-- These tests require `thelpers` because --headless/--embed
-- does not initialize the TUI.
describe("tui 't_Co' (terminal colors)", function()
local screen
local is_freebsd = (helpers.eval("system('uname') =~? 'FreeBSD'") == 1)
local is_freebsd = (string.lower(global_helpers.uname()) == 'freebsd')
local function assert_term_colors(term, colorterm, maxcolors)
helpers.clear({env={TERM=term}, args={}})