Merge remote-tracking branch 'upstream/master'

This commit is contained in:
ckelsel
2017-09-10 16:43:01 +08:00
31 changed files with 653 additions and 309 deletions

View File

@@ -11,6 +11,18 @@ if [[ "${TRAVIS_OS_NAME}" == osx ]]; then
brew update
fi
echo 'python info:'
(
2>&1 python --version || true
2>&1 python2 --version || true
2>&1 python3 --version || true
2>&1 pip --version || true
2>&1 pip2 --version || true
2>&1 pip3 --version || true
echo 'pyenv versions:'
2>&1 pyenv versions || true
) | sed 's/^/ /'
echo "Upgrade Python 2 pip."
pip2.7 -q install --user --upgrade pip
@@ -20,6 +32,10 @@ if [[ "${TRAVIS_OS_NAME}" == osx ]]; then
echo "Upgrade Python 3 pip."
pip3 -q install --user --upgrade pip
else
echo "Upgrade Python 3 pip."
pip3 -q install --user --upgrade pip
if command -v pip3 ; then
echo "Upgrade Python 3 pip."
pip3 -q install --user --upgrade pip
else
echo 'warning: missing pip3'
fi
fi

View File

@@ -239,7 +239,7 @@ function! s:check_python(version) abort
let pyname = 'python'.(a:version == 2 ? '' : '3')
let pyenv = resolve(exepath('pyenv'))
let pyenv_root = exists('$PYENV_ROOT') ? resolve($PYENV_ROOT) : 'n'
let pyenv_root = exists('$PYENV_ROOT') ? resolve($PYENV_ROOT) : ''
let venv = exists('$VIRTUAL_ENV') ? resolve($VIRTUAL_ENV) : ''
let host_prog_var = pyname.'_host_prog'
let loaded_var = 'g:loaded_'.pyname.'_provider'
@@ -251,6 +251,19 @@ function! s:check_python(version) abort
return
endif
if !empty(pyenv)
if empty(pyenv_root)
call health#report_warn(
\ 'pyenv was found, but $PYENV_ROOT is not set.',
\ ['Did you follow the final install instructions?',
\ 'If you use a shell "framework" like Prezto or Oh My Zsh, try without.',
\ 'Try a different shell (bash).']
\ )
else
call health#report_ok(printf('pyenv found: "%s"', pyenv))
endif
endif
if exists('g:'.host_prog_var)
call health#report_info(printf('Using: g:%s = "%s"', host_prog_var, get(g:, host_prog_var)))
endif
@@ -282,15 +295,6 @@ function! s:check_python(version) abort
endif
if !empty(pyenv)
if empty(pyenv_root)
call health#report_warn(
\ 'pyenv was found, but $PYENV_ROOT is not set.',
\ ['Did you follow the final install instructions?']
\ )
else
call health#report_ok(printf('pyenv found: "%s"', pyenv))
endif
let python_bin = s:trim(s:system([pyenv, 'which', pyname], '', 1))
if empty(python_bin)
@@ -320,9 +324,8 @@ function! s:check_python(version) abort
if python_bin =~# '\<shims\>'
call health#report_warn(printf('`%s` appears to be a pyenv shim.', python_bin), [
\ 'The `pyenv` executable is not in $PATH,',
\ 'Your pyenv installation is broken. You should set '
\ . '`g:'.host_prog_var.'` to avoid surprises.',
\ '`pyenv` is not in $PATH, your pyenv installation is broken. '
\ .'Set `g:'.host_prog_var.'` to avoid surprises.',
\ ])
endif
endif
@@ -335,7 +338,7 @@ function! s:check_python(version) abort
call health#report_warn('pyenv is not set up optimally.', [
\ printf('Create a virtualenv specifically '
\ . 'for Neovim using pyenv, and set `g:%s`. This will avoid '
\ . 'the need to install Neovim''s Python module in each '
\ . 'the need to install the Neovim Python module in each '
\ . 'version/virtualenv.', host_prog_var)
\ ])
elseif !empty(venv) && exists('g:'.host_prog_var)

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:
@@ -2406,6 +2398,7 @@ void set_completion(colnr_T startcol, list_T *list)
ins_compl_prep(' ');
}
ins_compl_clear();
ins_compl_free();
compl_direction = FORWARD;
if (startcol > curwin->w_cursor.col)
@@ -3166,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

@@ -3332,10 +3332,12 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout)
sub = regtilde(sub, p_magic);
// Check for a match on each line.
// If preview: limit to max('cmdwinheight', viewport).
linenr_T line2 = eap->line2;
for (linenr_T lnum = eap->line1;
lnum <= line2 && !(got_quit || aborting())
&& (!preview || matched_lines.size <= (size_t)p_cwh);
lnum <= line2 && !got_quit && !aborting()
&& (!preview || matched_lines.size < (size_t)p_cwh
|| lnum <= curwin->w_botline);
lnum++) {
long nmatch = vim_regexec_multi(&regmatch, curwin, curbuf, lnum,
(colnr_T)0, NULL);

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

@@ -2164,16 +2164,21 @@ void do_check_cursorbind(void)
int restart_edit_save = restart_edit;
restart_edit = true;
check_cursor();
if (curwin->w_p_cul || curwin->w_p_cuc) {
validate_cursor();
}
restart_edit = restart_edit_save;
}
/* Correct cursor for multi-byte character. */
if (has_mbyte)
// Correct cursor for multi-byte character.
if (has_mbyte) {
mb_adjust_cursor();
}
redraw_later(VALID);
/* Only scroll when 'scrollbind' hasn't done this. */
if (!curwin->w_p_scb)
// Only scroll when 'scrollbind' hasn't done this.
if (!curwin->w_p_scb) {
update_topline();
}
curwin->w_redr_status = true;
}
}

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[]. */
@@ -7958,18 +7956,7 @@ static void nv_event(cmdarg_T *cap)
may_garbage_collect = false;
multiqueue_process_events(main_loop.events);
cap->retval |= CA_COMMAND_BUSY; // don't call edit() now
}
/// 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);
finish_op = false;
}
/*

View File

@@ -5847,7 +5847,7 @@ static void screen_start_highlight(int attr)
ui_start_highlight(attr);
}
void screen_stop_highlight(void)
static void screen_stop_highlight(void)
{
ui_stop_highlight();
screen_attr = 0;

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;
@@ -530,6 +522,12 @@ void terminal_send(Terminal *term, char *data, size_t size)
void terminal_send_key(Terminal *term, int c)
{
VTermModifier mod = VTERM_MOD_NONE;
// Convert K_ZERO back to ASCII
if (c == K_ZERO) {
c = Ctrl_AT;
}
VTermKey key = convert_key(c, &mod);
if (key) {
@@ -783,26 +781,60 @@ static int term_sb_pop(int cols, VTermScreenCell *cells, void *data)
// }}}
// input handling {{{
static void convert_modifiers(VTermModifier *statep)
static void convert_modifiers(int key, VTermModifier *statep)
{
if (mod_mask & MOD_MASK_SHIFT) { *statep |= VTERM_MOD_SHIFT; }
if (mod_mask & MOD_MASK_CTRL) { *statep |= VTERM_MOD_CTRL; }
if (mod_mask & MOD_MASK_ALT) { *statep |= VTERM_MOD_ALT; }
switch (key) {
case K_S_TAB:
case K_S_UP:
case K_S_DOWN:
case K_S_LEFT:
case K_S_RIGHT:
case K_S_F1:
case K_S_F2:
case K_S_F3:
case K_S_F4:
case K_S_F5:
case K_S_F6:
case K_S_F7:
case K_S_F8:
case K_S_F9:
case K_S_F10:
case K_S_F11:
case K_S_F12:
*statep |= VTERM_MOD_SHIFT;
break;
case K_C_LEFT:
case K_C_RIGHT:
*statep |= VTERM_MOD_CTRL;
break;
}
}
static VTermKey convert_key(int key, VTermModifier *statep)
{
convert_modifiers(statep);
convert_modifiers(key, statep);
switch (key) {
case K_BS: return VTERM_KEY_BACKSPACE;
case K_S_TAB: // FALLTHROUGH
case TAB: return VTERM_KEY_TAB;
case Ctrl_M: return VTERM_KEY_ENTER;
case ESC: return VTERM_KEY_ESCAPE;
case K_S_UP: // FALLTHROUGH
case K_UP: return VTERM_KEY_UP;
case K_S_DOWN: // FALLTHROUGH
case K_DOWN: return VTERM_KEY_DOWN;
case K_S_LEFT: // FALLTHROUGH
case K_C_LEFT: // FALLTHROUGH
case K_LEFT: return VTERM_KEY_LEFT;
case K_S_RIGHT: // FALLTHROUGH
case K_C_RIGHT: // FALLTHROUGH
case K_RIGHT: return VTERM_KEY_RIGHT;
case K_INS: return VTERM_KEY_INS;
@@ -812,22 +844,22 @@ static VTermKey convert_key(int key, VTermModifier *statep)
case K_PAGEUP: return VTERM_KEY_PAGEUP;
case K_PAGEDOWN: return VTERM_KEY_PAGEDOWN;
case K_K0:
case K_K0: // FALLTHROUGH
case K_KINS: return VTERM_KEY_KP_0;
case K_K1:
case K_K1: // FALLTHROUGH
case K_KEND: return VTERM_KEY_KP_1;
case K_K2: return VTERM_KEY_KP_2;
case K_K3:
case K_K3: // FALLTHROUGH
case K_KPAGEDOWN: return VTERM_KEY_KP_3;
case K_K4: return VTERM_KEY_KP_4;
case K_K5: return VTERM_KEY_KP_5;
case K_K6: return VTERM_KEY_KP_6;
case K_K7:
case K_K7: // FALLTHROUGH
case K_KHOME: return VTERM_KEY_KP_7;
case K_K8: return VTERM_KEY_KP_8;
case K_K9:
case K_K9: // FALLTHROUGH
case K_KPAGEUP: return VTERM_KEY_KP_9;
case K_KDEL:
case K_KDEL: // FALLTHROUGH
case K_KPOINT: return VTERM_KEY_KP_PERIOD;
case K_KENTER: return VTERM_KEY_KP_ENTER;
case K_KPLUS: return VTERM_KEY_KP_PLUS;
@@ -835,6 +867,57 @@ static VTermKey convert_key(int key, VTermModifier *statep)
case K_KMULTIPLY: return VTERM_KEY_KP_MULT;
case K_KDIVIDE: return VTERM_KEY_KP_DIVIDE;
case K_S_F1: // FALLTHROUGH
case K_F1: return VTERM_KEY_FUNCTION(1);
case K_S_F2: // FALLTHROUGH
case K_F2: return VTERM_KEY_FUNCTION(2);
case K_S_F3: // FALLTHROUGH
case K_F3: return VTERM_KEY_FUNCTION(3);
case K_S_F4: // FALLTHROUGH
case K_F4: return VTERM_KEY_FUNCTION(4);
case K_S_F5: // FALLTHROUGH
case K_F5: return VTERM_KEY_FUNCTION(5);
case K_S_F6: // FALLTHROUGH
case K_F6: return VTERM_KEY_FUNCTION(6);
case K_S_F7: // FALLTHROUGH
case K_F7: return VTERM_KEY_FUNCTION(7);
case K_S_F8: // FALLTHROUGH
case K_F8: return VTERM_KEY_FUNCTION(8);
case K_S_F9: // FALLTHROUGH
case K_F9: return VTERM_KEY_FUNCTION(9);
case K_S_F10: // FALLTHROUGH
case K_F10: return VTERM_KEY_FUNCTION(10);
case K_S_F11: // FALLTHROUGH
case K_F11: return VTERM_KEY_FUNCTION(11);
case K_S_F12: // FALLTHROUGH
case K_F12: return VTERM_KEY_FUNCTION(12);
case K_F13: return VTERM_KEY_FUNCTION(13);
case K_F14: return VTERM_KEY_FUNCTION(14);
case K_F15: return VTERM_KEY_FUNCTION(15);
case K_F16: return VTERM_KEY_FUNCTION(16);
case K_F17: return VTERM_KEY_FUNCTION(17);
case K_F18: return VTERM_KEY_FUNCTION(18);
case K_F19: return VTERM_KEY_FUNCTION(19);
case K_F20: return VTERM_KEY_FUNCTION(20);
case K_F21: return VTERM_KEY_FUNCTION(21);
case K_F22: return VTERM_KEY_FUNCTION(22);
case K_F23: return VTERM_KEY_FUNCTION(23);
case K_F24: return VTERM_KEY_FUNCTION(24);
case K_F25: return VTERM_KEY_FUNCTION(25);
case K_F26: return VTERM_KEY_FUNCTION(26);
case K_F27: return VTERM_KEY_FUNCTION(27);
case K_F28: return VTERM_KEY_FUNCTION(28);
case K_F29: return VTERM_KEY_FUNCTION(29);
case K_F30: return VTERM_KEY_FUNCTION(30);
case K_F31: return VTERM_KEY_FUNCTION(31);
case K_F32: return VTERM_KEY_FUNCTION(32);
case K_F33: return VTERM_KEY_FUNCTION(33);
case K_F34: return VTERM_KEY_FUNCTION(34);
case K_F35: return VTERM_KEY_FUNCTION(35);
case K_F36: return VTERM_KEY_FUNCTION(36);
case K_F37: return VTERM_KEY_FUNCTION(37);
default: return VTERM_KEY_NONE;
}
}
@@ -1176,6 +1259,10 @@ static void redraw(bool restore_cursor)
update_screen(0);
}
if (need_maketitle) { // Update title in terminal-mode. #7248
maketitle();
}
if (restore_cursor) {
ui_cursor_goto(save_row, save_col);
} else if (term) {

View File

@@ -230,9 +230,26 @@ func Test_paste_in_cmdline()
call feedkeys("f;:aaa \<C-R>\<C-A> bbb\<C-B>\"\<CR>", 'tx')
call assert_equal('"aaa a;b-c*d bbb', @:)
call feedkeys(":\<C-\>etoupper(getline(1))\<CR>\<C-B>\"\<CR>", 'tx')
call assert_equal('"ASDF.X /TMP/SOME VERYLONGWORD A;B-C*D ', @:)
bwipe!
endfunc
func Test_remove_char_in_cmdline()
call feedkeys(":abc def\<S-Left>\<Del>\<C-B>\"\<CR>", 'tx')
call assert_equal('"abc ef', @:)
call feedkeys(":abc def\<S-Left>\<BS>\<C-B>\"\<CR>", 'tx')
call assert_equal('"abcdef', @:)
call feedkeys(":abc def ghi\<S-Left>\<C-W>\<C-B>\"\<CR>", 'tx')
call assert_equal('"abc ghi', @:)
call feedkeys(":abc def\<S-Left>\<C-U>\<C-B>\"\<CR>", 'tx')
call assert_equal('"def', @:)
endfunc
func Test_illegal_address()
new
2;'(

View File

@@ -7,10 +7,10 @@ func! ListMonths()
if g:setting != ''
exe ":set" g:setting
endif
let mth=copy(g:months)
let mth = copy(g:months)
let entered = strcharpart(getline('.'),0,col('.'))
if !empty(entered)
let mth=filter(mth, 'v:val=~"^".entered')
let mth = filter(mth, 'v:val=~"^".entered')
endif
call complete(1, mth)
return ''
@@ -468,7 +468,7 @@ endfunc
" auto-wrap text.
func Test_completion_ctrl_e_without_autowrap()
new
let tw_save=&tw
let tw_save = &tw
set tw=78
let li = [
\ '" zzz',
@@ -478,7 +478,7 @@ func Test_completion_ctrl_e_without_autowrap()
call feedkeys("A\<C-X>\<C-N>\<C-E>\<Esc>", "tx")
call assert_equal(li, getline(1, '$'))
let &tw=tw_save
let &tw = tw_save
q!
endfunc
@@ -541,4 +541,33 @@ func Test_completion_comment_formatting()
bwipe!
endfunc
function! DummyCompleteSix()
call complete(1, ['Hello', 'World'])
return ''
endfunction
" complete() correctly clears the list of autocomplete candidates
func Test_completion_clear_candidate_list()
new
%d
" select first entry from the completion popup
call feedkeys("a xxx\<C-N>\<C-R>=DummyCompleteSix()\<CR>", "tx")
call assert_equal('Hello', getline(1))
%d
" select second entry from the completion popup
call feedkeys("a xxx\<C-N>\<C-R>=DummyCompleteSix()\<CR>\<C-N>", "tx")
call assert_equal('World', getline(1))
%d
" select original text
call feedkeys("a xxx\<C-N>\<C-R>=DummyCompleteSix()\<CR>\<C-N>\<C-N>", "tx")
call assert_equal(' xxx', getline(1))
%d
" back at first entry from completion list
call feedkeys("a xxx\<C-N>\<C-R>=DummyCompleteSix()\<CR>\<C-N>\<C-N>\<C-N>", "tx")
call assert_equal('Hello', getline(1))
bw!
endfunc
" vim: shiftwidth=2 sts=2 expandtab

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

@@ -1448,7 +1448,7 @@ static void patch_terminfo_bugs(TUIData *data, const char *term,
// teminfo entries. See
// https://github.com/gnachman/iTerm2/pull/92 for more.
// xterm even has an extended version that has a vertical bar.
if (true_xterm // per xterm ctlseqs doco (since version 282)
if (!konsole && (true_xterm // per xterm ctlseqs doco (since version 282)
// per MinTTY 0.4.3-1 release notes from 2009
|| putty
// per https://bugzilla.gnome.org/show_bug.cgi?id=720821
@@ -1463,7 +1463,7 @@ static void patch_terminfo_bugs(TUIData *data, const char *term,
// Allows forcing the use of DECSCUSR on linux type terminals, such as
// console-terminal-emulator from the nosh toolset, which does indeed
// implement the xterm extension:
|| (linuxvt && (xterm_version || (vte_version > 0) || colorterm))) {
|| (linuxvt && (xterm_version || (vte_version > 0) || colorterm)))) {
data->unibi_ext.set_cursor_style =
(int)unibi_add_ext_str(ut, "Ss", "\x1b[%p1%d q");
if (-1 == data->unibi_ext.reset_cursor_style) {

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

@@ -705,7 +705,7 @@ static const int included_patches[] = {
250,
// 249 NA
// 248,
// 247,
247,
// 246 NA
// 245,
// 244,
@@ -764,14 +764,14 @@ static const int included_patches[] = {
// 191 NA
190,
// 189,
// 188,
188,
// 187 NA
// 186,
// 185,
// 184,
// 183,
// 182,
// 181,
182,
181,
// 180,
179,
178,
@@ -827,7 +827,7 @@ static const int included_patches[] = {
128,
127,
126,
// 125,
125,
124,
// 123 NA
// 122 NA

View File

@@ -329,24 +329,74 @@ describe('api', function()
}
eq({ { {mode='n', blocking=false},
13,
{mode='n', blocking=false}, -- TODO: should be blocked=true
{mode='n', blocking=false}, -- TODO: should be blocked=true ?
1 },
NIL}, meths.call_atomic(req))
eq({mode='r', blocking=true}, nvim("get_mode"))
end)
-- TODO: bug #6166
it("during insert-mode map-pending, returns blocking=true #6166", function()
command("inoremap xx foo")
nvim("input", "ix")
eq({mode='i', blocking=true}, nvim("get_mode"))
end)
-- TODO: bug #6166
it("during normal-mode gU, returns blocking=false #6166", function()
nvim("input", "gu")
eq({mode='no', blocking=false}, nvim("get_mode"))
end)
end)
describe('RPC (K_EVENT) #6166', function()
it('does not complete ("interrupt") normal-mode operator-pending', function()
helpers.insert([[
FIRST LINE
SECOND LINE]])
nvim('input', 'gg')
nvim('input', 'gu')
-- Make any RPC request (can be non-async: op-pending does not block).
nvim('get_current_buf')
-- Buffer should not change.
helpers.expect([[
FIRST LINE
SECOND LINE]])
-- Now send input to complete the operator.
nvim('input', 'j')
helpers.expect([[
first line
second line]])
end)
it('does not complete ("interrupt") normal-mode map-pending', function()
command("nnoremap dd :let g:foo='it worked...'<CR>")
helpers.insert([[
FIRST LINE
SECOND LINE]])
nvim('input', 'gg')
nvim('input', 'd')
-- Make any RPC request (must be async, because map-pending blocks).
nvim('get_api_info')
-- Send input to complete the mapping.
nvim('input', 'd')
helpers.expect([[
FIRST LINE
SECOND LINE]])
eq('it worked...', helpers.eval('g:foo'))
end)
it('does not complete ("interrupt") insert-mode map-pending', function()
command('inoremap xx foo')
command('set timeoutlen=9999')
helpers.insert([[
FIRST LINE
SECOND LINE]])
nvim('input', 'ix')
-- Make any RPC request (must be async, because map-pending blocks).
nvim('get_api_info')
-- Send input to complete the mapping.
nvim('input', 'x')
helpers.expect([[
FIRST LINE
SECOND LINfooE]])
end)
end)
describe('nvim_replace_termcodes', function()
it('escapes K_SPECIAL as K_SPECIAL KS_SPECIAL KE_FILLER', function()
eq('\128\254X', helpers.nvim('replace_termcodes', '\128', true, true, true))

View File

@@ -3,6 +3,7 @@ local Screen = require('test.functional.ui.screen')
local clear, wait, nvim = helpers.clear, helpers.wait, helpers.nvim
local nvim_dir, source, eq = helpers.nvim_dir, helpers.source, helpers.eq
local feed_command, eval = helpers.feed_command, helpers.eval
local retry = helpers.retry
local iswin = helpers.iswin
describe(':terminal', function()
@@ -70,19 +71,19 @@ describe(':terminal (with fake shell)', function()
it('with no argument, acts like termopen()', function()
terminal_with_fake_shell()
wait()
retry(3, 4 * screen.timeout, function()
screen:expect([[
^ready $ |
[Process exited 0] |
|
:terminal |
]])
end)
end)
it("with no argument, and 'shell' is set to empty string", function()
nvim('set_option', 'shell', '')
terminal_with_fake_shell()
wait()
screen:expect([[
^ |
~ |
@@ -94,7 +95,6 @@ describe(':terminal (with fake shell)', function()
it("with no argument, but 'shell' has arguments, acts like termopen()", function()
nvim('set_option', 'shell', nvim_dir..'/shell-test -t jeff')
terminal_with_fake_shell()
wait()
screen:expect([[
^jeff $ |
[Process exited 0] |
@@ -105,7 +105,6 @@ describe(':terminal (with fake shell)', function()
it('executes a given command through the shell', function()
terminal_with_fake_shell('echo hi')
wait()
screen:expect([[
^ready $ echo hi |
|
@@ -117,7 +116,6 @@ describe(':terminal (with fake shell)', function()
it("executes a given command through the shell, when 'shell' has arguments", function()
nvim('set_option', 'shell', nvim_dir..'/shell-test -t jeff')
terminal_with_fake_shell('echo hi')
wait()
screen:expect([[
^jeff $ echo hi |
|
@@ -128,7 +126,6 @@ describe(':terminal (with fake shell)', function()
it('allows quotes and slashes', function()
terminal_with_fake_shell([[echo 'hello' \ "world"]])
wait()
screen:expect([[
^ready $ echo 'hello' \ "world" |
|
@@ -164,7 +161,6 @@ describe(':terminal (with fake shell)', function()
it('works with :find', function()
terminal_with_fake_shell()
wait()
screen:expect([[
^ready $ |
[Process exited 0] |

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,48 @@ 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")
retry(2, 3 * screen.timeout, function()
-- 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)
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 +349,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={}})

View File

@@ -892,6 +892,31 @@ describe(":substitute, inccommand=split", function()
]])
end)
it('previews correctly when previewhight is small', function()
feed_command('set cwh=3')
feed_command('set hls')
feed('ggdG')
insert(string.rep('abc abc abc\n', 20))
feed(':%s/abc/MMM/g')
screen:expect([[
MMM MMM MMM |
MMM MMM MMM |
MMM MMM MMM |
MMM MMM MMM |
MMM MMM MMM |
MMM MMM MMM |
MMM MMM MMM |
MMM MMM MMM |
MMM MMM MMM |
{11:[No Name] [+] }|
| 1| {12:MMM} {12:MMM} {12:MMM} |
| 2| {12:MMM} {12:MMM} {12:MMM} |
| 3| {12:MMM} {12:MMM} {12:MMM} |
{10:[Preview] }|
:%s/abc/MMM/g^ |
]])
end)
it('actually replaces text', function()
feed(":%s/tw/XX/g<Enter>")