Compare commits

...

15 Commits

Author SHA1 Message Date
52dbb5ea7f patch 8.0.1330: MS-Windows: job in terminal can't get back to Vim
Problem:    MS-Windows: job in terminal can't get back to Vim.
Solution:   set VIM_SERVERNAME in the environment. (Yasuhiro Matsumoto, closes
            #2360)
2017-11-21 18:11:27 +01:00
5505860152 patch 8.0.1329: when a flaky test fails it also often fails the second time
Problem:    When a flaky test fails it also often fails the second time.
Solution:   Sleep a couple of seconds before the second try.
2017-11-21 15:14:51 +01:00
ff5467965e patch 8.0.1328: trouble when using ":term ++close" with autocmd
Problem:    Trouble when using ":term ++close" with autocmd. (Gabriel Barta)
Solution:   Use aucmd_prepbuf() and aucmd_restbuf() instead of setting curbuf.
            (closes #2339)
2017-11-21 14:47:57 +01:00
91ffda9852 patch 8.0.1327: new proto file missing from distribution
Problem:    New proto file missing from distribution.
Solution:   Add it. (closes #2355)
2017-11-21 13:52:14 +01:00
6e77df2d85 patch 8.0.1326: largefile test fails on CI, glob test on MS-Windows
Problem:    Largefile test fails on CI, glob test on MS-Windows.
Solution:   Remove largefile test from list of all tests. Don't run
            Test_glob() on non-unix systems.  More cleanup. (Yegappan
            Lakshmanan, closes #2354)
2017-11-21 11:43:08 +01:00
5df95ea9ef patch 8.0.1325: more tests are not run
Problem:    More tests are not run.
Solution:   Add targets to the list of tests. (Yegappan Lakshmanan)
2017-11-20 22:08:10 +01:00
bb160a188a patch 8.0.1324: some xterm sends different mouse move codes
Problem:    Some xterm sends different mouse move codes.
Solution:   Also accept 0x80 as a move event.
2017-11-20 21:52:24 +01:00
73675fbc48 patch 8.0.1323: mouse events in a terminal window may cause endless loop
Problem:    Mouse events in a terminal window may cause endless loop.
Solution:   Adjust position computation.  Don't stuff a mouse event when
            coming from normal_cmd().
2017-11-20 21:49:19 +01:00
5bbef31949 patch 8.0.1322: textformat test isn't run
Problem:    Textformat test isn't run. (Yegappan Lakshmanan)
Solution:   Add target to the list of tests.
2017-11-19 20:38:05 +01:00
40e280d949 patch 8.0.1321: can't build huge version with Athena
Problem:    Can't build huge version with Athena. (Mark Kelly)
Solution:   Move including beval.h to before structs.h. Include beval.pro like
            other proto files.
2017-11-19 20:34:59 +01:00
7221fce8b3 patch 8.0.1320: popup test fails on GUI-only build
Problem:    Popup test fails on GUI-only build.
Solution:   Don't test balloon_split() when it's not available.
2017-11-19 20:32:49 +01:00
669a828cdc patch 8.0.1319: can't build GUI on MS-Windows
Problem:    Can't build GUI on MS-Windows.
Solution:   Don't define the balloon_split() function in a GUI-only build.
2017-11-19 20:13:05 +01:00
246fe03d15 patch 8.0.1318: terminal balloon only shows one line
Problem:    Terminal balloon only shows one line.
Solution:   Split into several lines in a clever way.  Add balloon_split().
            Make balloon_show() accept a list in the terminal.
2017-11-19 19:56:27 +01:00
e518226713 patch 8.0.1317: accessing freed memory in term_wait()
Problem:    Accessing freed memory in term_wait(). (Dominique Pelle)
Solution:   Check that the buffer still exists.
2017-11-19 15:05:44 +01:00
44c2bffde7 patch 8.0.1316: build still still fails on Mac
Problem:    Build still still fails on Mac. (chdiza)
Solution:   Remove another bogus typedef.
2017-11-18 23:23:01 +01:00
25 changed files with 484 additions and 80 deletions

View File

@ -141,6 +141,7 @@ SRC_ALL = \
src/testdir/xterm_ramp.vim \ src/testdir/xterm_ramp.vim \
src/proto.h \ src/proto.h \
src/proto/arabic.pro \ src/proto/arabic.pro \
src/proto/beval.pro \
src/proto/blowfish.pro \ src/proto/blowfish.pro \
src/proto/buffer.pro \ src/proto/buffer.pro \
src/proto/channel.pro \ src/proto/channel.pro \

View File

@ -2032,6 +2032,7 @@ asin({expr}) Float arc sine of {expr}
atan({expr}) Float arc tangent of {expr} atan({expr}) Float arc tangent of {expr}
atan2({expr1}, {expr2}) Float arc tangent of {expr1} / {expr2} atan2({expr1}, {expr2}) Float arc tangent of {expr1} / {expr2}
balloon_show({msg}) none show {msg} inside the balloon balloon_show({msg}) none show {msg} inside the balloon
balloon_split({msg}) List split {msg} as used for a balloon
browse({save}, {title}, {initdir}, {default}) browse({save}, {title}, {initdir}, {default})
String put up a file requester String put up a file requester
browsedir({title}, {initdir}) String put up a directory requester browsedir({title}, {initdir}) String put up a directory requester
@ -2682,8 +2683,12 @@ atan2({expr1}, {expr2}) *atan2()*
< 2.356194 < 2.356194
{only available when compiled with the |+float| feature} {only available when compiled with the |+float| feature}
balloon_show({msg}) *balloon_show()* balloon_show({expr}) *balloon_show()*
Show {msg} inside the balloon. Show {expr} inside the balloon. For the GUI {expr} is used as
a string. For a terminal {expr} can be a list, which contains
the lines of the balloon. If {expr} is not a list it will be
split with |balloon_split()|.
Example: > Example: >
func GetBalloonContent() func GetBalloonContent()
" initiate getting the content " initiate getting the content
@ -2703,7 +2708,16 @@ balloon_show({msg}) *balloon_show()*
When showing a balloon is not possible nothing happens, no When showing a balloon is not possible nothing happens, no
error message. error message.
{only available when compiled with the +balloon_eval feature} {only available when compiled with the +balloon_eval or
+balloon_eval_term feature}
balloon_split({msg}) *balloon_split()*
Split {msg} into lines to be displayed in a balloon. The
splits are made for the current window size and optimize to
show debugger output.
Returns a |List| with the split lines.
{only available when compiled with the +balloon_eval_term
feature}
*browse()* *browse()*
browse({save}, {title}, {initdir}, {default}) browse({save}, {title}, {initdir}, {default})

View File

@ -1,4 +1,4 @@
*terminal.txt* For Vim version 8.0. Last change: 2017 Nov 12 *terminal.txt* For Vim version 8.0. Last change: 2017 Nov 17
VIM REFERENCE MANUAL by Bram Moolenaar VIM REFERENCE MANUAL by Bram Moolenaar
@ -106,6 +106,10 @@ BufWinEnter autocommand event is triggered. This makes it possible to set
options specifically for the window and buffer. Example: > options specifically for the window and buffer. Example: >
au BufWinEnter * if &buftype == 'terminal' | setlocal bufhidden=hide | endif au BufWinEnter * if &buftype == 'terminal' | setlocal bufhidden=hide | endif
Mouse events (click and drag) are passed to the terminal. Mouse move events
are only passed when Vim itself is receiving them. For a terminal that is
when 'balloonevalterm' is enabled.
Size and color ~ Size and color ~
*terminal-size-color* *terminal-size-color*
@ -335,6 +339,9 @@ to point to the right file, if needed. If you have both the 32-bit and 64-bit
version, rename to winpty32.dll and winpty64.dll to match the way Vim was version, rename to winpty32.dll and winpty64.dll to match the way Vim was
build. build.
Environment variables are used to pass information to the running job:
VIM_SERVERNAME v:servername
============================================================================== ==============================================================================
2. Remote testing *terminal-testing* 2. Remote testing *terminal-testing*

View File

@ -127,9 +127,11 @@ func s:StartDebug(cmd)
call win_gotoid(s:gdbwin) call win_gotoid(s:gdbwin)
" Enable showing a balloon with eval info " Enable showing a balloon with eval info
if has("balloon_eval") if has("balloon_eval") || has("balloon_eval_term")
set ballooneval
set balloonexpr=TermDebugBalloonExpr() set balloonexpr=TermDebugBalloonExpr()
if has("balloon_eval")
set ballooneval
endif
if has("balloon_eval_term") if has("balloon_eval_term")
set balloonevalterm set balloonevalterm
endif endif
@ -158,9 +160,11 @@ func s:EndDebug(job, status)
let &columns = s:save_columns let &columns = s:save_columns
endif endif
if has("balloon_eval") if has("balloon_eval") || has("balloon_eval_term")
set noballooneval
set balloonexpr= set balloonexpr=
if has("balloon_eval")
set noballooneval
endif
if has("balloon_eval_term") if has("balloon_eval_term")
set noballoonevalterm set noballoonevalterm
endif endif
@ -366,6 +370,7 @@ func s:HandleError(msg)
if a:msg =~ 'No symbol .* in current context' if a:msg =~ 'No symbol .* in current context'
\ || a:msg =~ 'Cannot access memory at address ' \ || a:msg =~ 'Cannot access memory at address '
\ || a:msg =~ 'Attempt to use a type name as an expression' \ || a:msg =~ 'Attempt to use a type name as an expression'
\ || a:msg =~ 'A syntax error in expression,'
" Result of s:SendEval() failed, ignore. " Result of s:SendEval() failed, ignore.
return return
endif endif

View File

@ -134,19 +134,20 @@ get_beval_info(
} }
/* /*
* Show a balloon with "mesg". * Show a balloon with "mesg" or "list".
*/ */
void void
post_balloon(BalloonEval *beval UNUSED, char_u *mesg) post_balloon(BalloonEval *beval UNUSED, char_u *mesg, list_T *list)
{ {
# ifdef FEAT_BEVAL_TERM # ifdef FEAT_BEVAL_TERM
# ifdef FEAT_GUI # ifdef FEAT_GUI
if (!gui.in_use) if (!gui.in_use)
# endif # endif
ui_post_balloon(mesg); ui_post_balloon(mesg, list);
# endif # endif
# ifdef FEAT_BEVAL_GUI # ifdef FEAT_BEVAL_GUI
if (gui.in_use) if (gui.in_use)
/* GUI can't handle a list */
gui_mch_post_balloon(beval, mesg); gui_mch_post_balloon(beval, mesg);
# endif # endif
} }
@ -257,7 +258,7 @@ general_beval_cb(BalloonEval *beval, int state UNUSED)
set_vim_var_string(VV_BEVAL_TEXT, NULL, -1); set_vim_var_string(VV_BEVAL_TEXT, NULL, -1);
if (result != NULL && result[0] != NUL) if (result != NULL && result[0] != NUL)
{ {
post_balloon(beval, result); post_balloon(beval, result, NULL);
recursive = FALSE; recursive = FALSE;
return; return;
} }

View File

@ -78,7 +78,6 @@ typedef struct BalloonEvalStruct
#define EVAL_OFFSET_X 15 /* displacement of beval topleft corner from pointer */ #define EVAL_OFFSET_X 15 /* displacement of beval topleft corner from pointer */
#define EVAL_OFFSET_Y 10 #define EVAL_OFFSET_Y 10
#include "beval.pro"
#ifdef FEAT_BEVAL_GUI #ifdef FEAT_BEVAL_GUI
# include "gui_beval.pro" # include "gui_beval.pro"
#endif #endif

View File

@ -61,6 +61,9 @@ static void f_atan2(typval_T *argvars, typval_T *rettv);
#endif #endif
#ifdef FEAT_BEVAL #ifdef FEAT_BEVAL
static void f_balloon_show(typval_T *argvars, typval_T *rettv); static void f_balloon_show(typval_T *argvars, typval_T *rettv);
# if defined(FEAT_BEVAL_TERM)
static void f_balloon_split(typval_T *argvars, typval_T *rettv);
# endif
#endif #endif
static void f_browse(typval_T *argvars, typval_T *rettv); static void f_browse(typval_T *argvars, typval_T *rettv);
static void f_browsedir(typval_T *argvars, typval_T *rettv); static void f_browsedir(typval_T *argvars, typval_T *rettv);
@ -494,6 +497,9 @@ static struct fst
#endif #endif
#ifdef FEAT_BEVAL #ifdef FEAT_BEVAL
{"balloon_show", 1, 1, f_balloon_show}, {"balloon_show", 1, 1, f_balloon_show},
# if defined(FEAT_BEVAL_TERM)
{"balloon_split", 1, 1, f_balloon_split},
# endif
#endif #endif
{"browse", 4, 4, f_browse}, {"browse", 4, 4, f_browse},
{"browsedir", 2, 2, f_browsedir}, {"browsedir", 2, 2, f_browsedir},
@ -1410,8 +1416,40 @@ f_atan2(typval_T *argvars, typval_T *rettv)
f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED) f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
{ {
if (balloonEval != NULL) if (balloonEval != NULL)
post_balloon(balloonEval, get_tv_string_chk(&argvars[0])); {
if (argvars[0].v_type == VAR_LIST
# ifdef FEAT_GUI
&& !gui.in_use
# endif
)
post_balloon(balloonEval, NULL, argvars[0].vval.v_list);
else
post_balloon(balloonEval, get_tv_string_chk(&argvars[0]), NULL);
}
} }
# if defined(FEAT_BEVAL_TERM)
static void
f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
{
if (rettv_list_alloc(rettv) == OK)
{
char_u *msg = get_tv_string_chk(&argvars[0]);
if (msg != NULL)
{
pumitem_T *array;
int size = split_message(msg, &array);
int i;
/* Skip the first and last item, they are always empty. */
for (i = 1; i < size - 1; ++i)
list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
vim_free(array);
}
}
}
# endif
#endif #endif
/* /*

View File

@ -4633,7 +4633,9 @@ nv_mousescroll(cmdarg_T *cap)
{ {
# ifdef FEAT_TERMINAL # ifdef FEAT_TERMINAL
if (term_use_loop()) if (term_use_loop())
send_keys_to_term(curbuf->b_term, cap->cmdchar, TRUE); /* This window is a terminal window, send the mouse event there.
* Set "typed" to FALSE to avoid an endless loop. */
send_keys_to_term(curbuf->b_term, cap->cmdchar, FALSE);
else else
# endif # endif
if (mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL)) if (mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL))

View File

@ -14,7 +14,6 @@
*/ */
#define NO_X11_INCLUDES #define NO_X11_INCLUDES
typedef int BalloonEval; /* used in header files */
#include "vim.h" #include "vim.h"

View File

@ -5034,10 +5034,10 @@ job_io_file_open(
* environment argument of vim_create_process(). * environment argument of vim_create_process().
*/ */
void void
win32_build_env(dict_T *env, garray_T *gap) win32_build_env(dict_T *env, garray_T *gap, int is_terminal)
{ {
hashitem_T *hi; hashitem_T *hi;
int todo = (int)env->dv_hashtab.ht_used; long_u todo = env != NULL ? env->dv_hashtab.ht_used : 0;
LPVOID base = GetEnvironmentStringsW(); LPVOID base = GetEnvironmentStringsW();
/* for last \0 */ /* for last \0 */
@ -5062,35 +5062,56 @@ win32_build_env(dict_T *env, garray_T *gap)
*((WCHAR*)gap->ga_data + gap->ga_len++) = L'\0'; *((WCHAR*)gap->ga_data + gap->ga_len++) = L'\0';
} }
for (hi = env->dv_hashtab.ht_array; todo > 0; ++hi) if (env != NULL)
{ {
if (!HASHITEM_EMPTY(hi)) for (hi = env->dv_hashtab.ht_array; todo > 0; ++hi)
{ {
typval_T *item = &dict_lookup(hi)->di_tv; if (!HASHITEM_EMPTY(hi))
WCHAR *wkey = enc_to_utf16((char_u *)hi->hi_key, NULL);
WCHAR *wval = enc_to_utf16(get_tv_string(item), NULL);
--todo;
if (wkey != NULL && wval != NULL)
{ {
size_t n; typval_T *item = &dict_lookup(hi)->di_tv;
size_t lkey = wcslen(wkey); WCHAR *wkey = enc_to_utf16((char_u *)hi->hi_key, NULL);
size_t lval = wcslen(wval); WCHAR *wval = enc_to_utf16(get_tv_string(item), NULL);
--todo;
if (wkey != NULL && wval != NULL)
{
size_t n;
size_t lkey = wcslen(wkey);
size_t lval = wcslen(wval);
if (ga_grow(gap, (int)(lkey + lval + 2)) != OK) if (ga_grow(gap, (int)(lkey + lval + 2)) != OK)
continue; continue;
for (n = 0; n < lkey; n++) for (n = 0; n < lkey; n++)
*((WCHAR*)gap->ga_data + gap->ga_len++) = wkey[n]; *((WCHAR*)gap->ga_data + gap->ga_len++) = wkey[n];
*((WCHAR*)gap->ga_data + gap->ga_len++) = L'='; *((WCHAR*)gap->ga_data + gap->ga_len++) = L'=';
for (n = 0; n < lval; n++) for (n = 0; n < lval; n++)
*((WCHAR*)gap->ga_data + gap->ga_len++) = wval[n]; *((WCHAR*)gap->ga_data + gap->ga_len++) = wval[n];
*((WCHAR*)gap->ga_data + gap->ga_len++) = L'\0'; *((WCHAR*)gap->ga_data + gap->ga_len++) = L'\0';
}
if (wkey != NULL) vim_free(wkey);
if (wval != NULL) vim_free(wval);
} }
if (wkey != NULL) vim_free(wkey);
if (wval != NULL) vim_free(wval);
} }
} }
*((WCHAR*)gap->ga_data + gap->ga_len++) = L'\0'; # ifdef FEAT_CLIENTSERVER
if (is_terminal)
{
char_u *servername = get_vim_var_str(VV_SEND_SERVER);
size_t lval = STRLEN(servername);
size_t n;
if (ga_grow(gap, (int)(14 + lval + 2)) == OK)
{
for (n = 0; n < 15; n++)
*((WCHAR*)gap->ga_data + gap->ga_len++) =
(WCHAR)"VIM_SERVERNAME="[n];
for (n = 0; n < lval; n++)
*((WCHAR*)gap->ga_data + gap->ga_len++) =
(WCHAR)servername[n];
*((WCHAR*)gap->ga_data + gap->ga_len++) = L'\0';
}
}
# endif
} }
void void
@ -5133,7 +5154,7 @@ mch_job_start(char *cmd, job_T *job, jobopt_T *options)
} }
if (options->jo_env != NULL) if (options->jo_env != NULL)
win32_build_env(options->jo_env, &ga); win32_build_env(options->jo_env, &ga, FALSE);
ZeroMemory(&pi, sizeof(pi)); ZeroMemory(&pi, sizeof(pi));
ZeroMemory(&si, sizeof(si)); ZeroMemory(&si, sizeof(si));

View File

@ -766,9 +766,147 @@ static int balloon_arraysize;
static int balloon_mouse_row = 0; static int balloon_mouse_row = 0;
static int balloon_mouse_col = 0; static int balloon_mouse_col = 0;
#define BALLOON_MIN_WIDTH 40 #define BALLOON_MIN_WIDTH 50
#define BALLOON_MIN_HEIGHT 10 #define BALLOON_MIN_HEIGHT 10
typedef struct {
char_u *start;
int bytelen;
int cells;
int indent;
} balpart_T;
/*
* Split a string into parts to display in the balloon.
* Aimed at output from gdb. Attempts to split at white space, preserve quoted
* strings and make a struct look good.
* Resulting array is stored in "array" and returns the size of the array.
*/
int
split_message(char_u *mesg, pumitem_T **array)
{
garray_T ga;
char_u *p;
balpart_T *item;
int quoted = FALSE;
int height;
int line;
int item_idx;
int indent = 0;
int max_cells = 0;
int max_height = Rows / 2 - 2;
int long_item_count = 0;
int split_long_items = FALSE;
ga_init2(&ga, sizeof(balpart_T), 20);
p = mesg;
while (*p != NUL)
{
if (ga_grow(&ga, 1) == FAIL)
goto failed;
item = ((balpart_T *)ga.ga_data) + ga.ga_len;
item->start = p;
item->indent = indent;
item->cells = indent * 2;
++ga.ga_len;
while (*p != NUL)
{
if (*p == '"')
quoted = !quoted;
else if (*p == '\\' && p[1] != NUL)
++p;
else if (!quoted)
{
if ((*p == ',' && p[1] == ' ') || *p == '{' || *p == '}')
{
/* Looks like a good point to break. */
if (*p == '{')
++indent;
else if (*p == '}' && indent > 0)
--indent;
++item->cells;
p = skipwhite(p + 1);
break;
}
}
item->cells += ptr2cells(p);
p += MB_PTR2LEN(p);
}
item->bytelen = p - item->start;
if (item->cells > max_cells)
max_cells = item->cells;
long_item_count += item->cells / BALLOON_MIN_WIDTH;
}
height = 2 + ga.ga_len;
/* If there are long items and the height is below the limit: split lines */
if (long_item_count > 0 && height + long_item_count <= max_height)
{
split_long_items = TRUE;
height += long_item_count;
}
/* Limit to half the window height, it has to fit above or below the mouse
* position. */
if (height > max_height)
height = max_height;
*array = (pumitem_T *)alloc_clear((unsigned)sizeof(pumitem_T) * height);
if (*array == NULL)
goto failed;
/* Add an empty line above and below, looks better. */
(*array)->pum_text = vim_strsave((char_u *)"");
(*array + height - 1)->pum_text = vim_strsave((char_u *)"");
for (line = 1, item_idx = 0; line < height - 1; ++item_idx)
{
int skip;
int thislen;
int copylen;
int ind;
int cells;
item = ((balpart_T *)ga.ga_data) + item_idx;
for (skip = 0; skip < item->bytelen; skip += thislen)
{
if (split_long_items && item->cells >= BALLOON_MIN_WIDTH)
{
cells = item->indent * 2;
for (p = item->start + skip; p < item->start + item->bytelen;
p += MB_PTR2LEN(p))
if ((cells += ptr2cells(p)) > BALLOON_MIN_WIDTH)
break;
thislen = p - (item->start + skip);
}
else
thislen = item->bytelen;
/* put indent at the start */
p = alloc(thislen + item->indent * 2 + 1);
for (ind = 0; ind < item->indent * 2; ++ind)
p[ind] = ' ';
/* exclude spaces at the end of the string */
for (copylen = thislen; copylen > 0; --copylen)
if (item->start[skip + copylen - 1] != ' ')
break;
vim_strncpy(p + ind, item->start + skip, copylen);
(*array)[line].pum_text = p;
item->indent = 0; /* wrapped line has no indent */
++line;
}
}
ga_clear(&ga);
return height;
failed:
ga_clear(&ga);
return 0;
}
void void
ui_remove_balloon(void) ui_remove_balloon(void)
{ {
@ -786,28 +924,42 @@ ui_remove_balloon(void)
* Terminal version of a balloon, uses the popup menu code. * Terminal version of a balloon, uses the popup menu code.
*/ */
void void
ui_post_balloon(char_u *mesg) ui_post_balloon(char_u *mesg, list_T *list)
{ {
ui_remove_balloon(); ui_remove_balloon();
/* TODO: split the text in multiple lines. */ if (mesg == NULL && list == NULL)
balloon_arraysize = 3; return;
balloon_array = (pumitem_T *)alloc_clear( if (list != NULL)
(unsigned)sizeof(pumitem_T) * balloon_arraysize);
if (balloon_array != NULL)
{ {
/* Add an empty line above and below, looks better. */ listitem_T *li;
balloon_array[0].pum_text = vim_strsave((char_u *)""); int idx;
balloon_array[1].pum_text = vim_strsave(mesg);
balloon_array[2].pum_text = vim_strsave((char_u *)"");
balloon_arraysize = list->lv_len;
balloon_array = (pumitem_T *)alloc_clear(
(unsigned)sizeof(pumitem_T) * list->lv_len);
if (balloon_array == NULL)
return;
for (idx = 0, li = list->lv_first; li != NULL; li = li->li_next, ++idx)
{
char_u *text = get_tv_string_chk(&li->li_tv);
balloon_array[idx].pum_text = vim_strsave(
text == NULL ? (char_u *)"" : text);
}
}
else
balloon_arraysize = split_message(mesg, &balloon_array);
if (balloon_arraysize > 0)
{
pum_array = balloon_array; pum_array = balloon_array;
pum_size = balloon_arraysize; pum_size = balloon_arraysize;
pum_compute_size(); pum_compute_size();
pum_scrollbar = 0; pum_scrollbar = 0;
pum_height = balloon_arraysize; pum_height = balloon_arraysize;
if (Rows - mouse_row > BALLOON_MIN_HEIGHT) if (Rows - mouse_row > pum_size)
{ {
/* Enough space below the mouse row. */ /* Enough space below the mouse row. */
pum_row = mouse_row + 1; pum_row = mouse_row + 1;
@ -817,7 +969,7 @@ ui_post_balloon(char_u *mesg)
else else
{ {
/* Show above the mouse row, reduce height if it does not fit. */ /* Show above the mouse row, reduce height if it does not fit. */
pum_row = mouse_row - 1 - pum_size; pum_row = mouse_row - pum_size;
if (pum_row < 0) if (pum_row < 0)
{ {
pum_height += pum_row; pum_height += pum_row;

View File

@ -201,7 +201,9 @@ void qsort(void *base, size_t elm_count, size_t elm_size, int (*cmp)(const void
/* Ugly solution for "BalloonEval" not being defined while it's used in some /* Ugly solution for "BalloonEval" not being defined while it's used in some
* .pro files. */ * .pro files. */
# ifndef FEAT_BEVAL # ifdef FEAT_BEVAL
# include "beval.pro"
# else
# define BalloonEval int # define BalloonEval int
# endif # endif

View File

@ -1,6 +1,6 @@
/* beval.c */ /* beval.c */
int get_beval_info(BalloonEval *beval, int getword, win_T **winp, linenr_T *lnump, char_u **textp, int *colp); int get_beval_info(BalloonEval *beval, int getword, win_T **winp, linenr_T *lnump, char_u **textp, int *colp);
void post_balloon(BalloonEval *beval, char_u *mesg); void post_balloon(BalloonEval *beval, char_u *mesg, list_T *list);
int can_use_beval(void); int can_use_beval(void);
void general_beval_cb(BalloonEval *beval, int state); void general_beval_cb(BalloonEval *beval, int state);
/* vim: set ft=c : */ /* vim: set ft=c : */

View File

@ -67,5 +67,5 @@ void used_file_arg(char *name, int literal, int full_path, int diff_mode);
void set_alist_count(void); void set_alist_count(void);
void fix_arg_enc(void); void fix_arg_enc(void);
int mch_setenv(char *var, char *value, int x); int mch_setenv(char *var, char *value, int x);
void win32_build_env(dict_T *l, garray_T *gap); void win32_build_env(dict_T *l, garray_T *gap, int is_terminal);
/* vim: set ft=c : */ /* vim: set ft=c : */

View File

@ -5,7 +5,8 @@ void pum_undisplay(void);
void pum_clear(void); void pum_clear(void);
int pum_visible(void); int pum_visible(void);
int pum_get_height(void); int pum_get_height(void);
int split_message(char_u *mesg, pumitem_T **array);
void ui_remove_balloon(void); void ui_remove_balloon(void);
void ui_post_balloon(char_u *mesg); void ui_post_balloon(char_u *mesg, list_T *list);
void ui_may_remove_balloon(void); void ui_may_remove_balloon(void);
/* vim: set ft=c : */ /* vim: set ft=c : */

View File

@ -4980,6 +4980,8 @@ check_termcode(
* add 0x08 for ALT * add 0x08 for ALT
* add 0x10 for CTRL * add 0x10 for CTRL
* add 0x20 for mouse drag (0x40 is drag with left button) * add 0x20 for mouse drag (0x40 is drag with left button)
* add 0x40 for mouse move (0x80 is move, 0x81 too)
* 0x43 (drag + release) is also move
* c == column + ' ' + 1 == column + 33 * c == column + ' ' + 1 == column + 33
* r == row + ' ' + 1 == row + 33 * r == row + ' ' + 1 == row + 33
* *
@ -5121,9 +5123,15 @@ check_termcode(
# endif # endif
) )
{ {
/* Keep the mouse_code before it's changed, so that we # if defined(UNIX) && defined(FEAT_MOUSE_TTY)
* remember that it was a mouse wheel click. */ if (use_xterm_mouse() > 1 && mouse_code >= 0x80)
wheel_code = mouse_code; /* mouse-move event, using MOUSE_DRAG works */
mouse_code = MOUSE_DRAG;
else
# endif
/* Keep the mouse_code before it's changed, so that we
* remember that it was a mouse wheel click. */
wheel_code = mouse_code;
} }
# ifdef FEAT_MOUSE_XTERM # ifdef FEAT_MOUSE_XTERM
else if (held_button == MOUSE_RELEASE else if (held_button == MOUSE_RELEASE

View File

@ -51,6 +51,7 @@
* - implement term_setsize() * - implement term_setsize()
* - Termdebug does not work when Vim build with mzscheme. gdb hangs. * - Termdebug does not work when Vim build with mzscheme. gdb hangs.
* - MS-Windows GUI: WinBar has tearoff item * - MS-Windows GUI: WinBar has tearoff item
* - Adding WinBar to terminal window doesn't display, text isn't shifted down.
* - MS-Windows GUI: still need to type a key after shell exits? #1924 * - MS-Windows GUI: still need to type a key after shell exits? #1924
* - After executing a shell command the status line isn't redraw. * - After executing a shell command the status line isn't redraw.
* - What to store in a session file? Shell at the prompt would be OK to * - What to store in a session file? Shell at the prompt would be OK to
@ -1302,9 +1303,9 @@ send_keys_to_term(term_T *term, int c, int typed)
case K_MOUSELEFT: case K_MOUSELEFT:
case K_MOUSERIGHT: case K_MOUSERIGHT:
if (mouse_row < W_WINROW(curwin) if (mouse_row < W_WINROW(curwin)
|| mouse_row >= (W_WINROW(curwin) + curwin->w_height) || mouse_row > (W_WINROW(curwin) + curwin->w_height)
|| mouse_col < curwin->w_wincol || mouse_col < curwin->w_wincol
|| mouse_col >= W_ENDCOL(curwin) || mouse_col > W_ENDCOL(curwin)
|| dragging_outside) || dragging_outside)
{ {
/* click or scroll outside the current window */ /* click or scroll outside the current window */
@ -2172,10 +2173,13 @@ term_channel_closed(channel_T *ch)
if (term->tl_finish == 'c') if (term->tl_finish == 'c')
{ {
aco_save_T aco;
/* ++close or term_finish == "close" */ /* ++close or term_finish == "close" */
ch_log(NULL, "terminal job finished, closing window"); ch_log(NULL, "terminal job finished, closing window");
curbuf = term->tl_buffer; aucmd_prepbuf(&aco, term->tl_buffer);
do_bufdel(DOBUF_WIPE, (char_u *)"", 1, fnum, fnum, FALSE); do_bufdel(DOBUF_WIPE, (char_u *)"", 1, fnum, fnum, FALSE);
aucmd_restbuf(&aco);
break; break;
} }
if (term->tl_finish == 'o' && term->tl_buffer->b_nwindows == 0) if (term->tl_finish == 'o' && term->tl_buffer->b_nwindows == 0)
@ -3227,6 +3231,10 @@ f_term_wait(typval_T *argvars, typval_T *rettv UNUSED)
{ {
mch_check_messages(); mch_check_messages();
parse_queued_messages(); parse_queued_messages();
if (!buf_valid(buf))
/* If the terminal is closed when the channel is closed the
* buffer disappears. */
break;
ui_delay(10L, FALSE); ui_delay(10L, FALSE);
} }
mch_check_messages(); mch_check_messages();
@ -3416,12 +3424,10 @@ term_and_job_init(
return FAIL; return FAIL;
if (opt->jo_cwd != NULL) if (opt->jo_cwd != NULL)
cwd_wchar = enc_to_utf16(opt->jo_cwd, NULL); cwd_wchar = enc_to_utf16(opt->jo_cwd, NULL);
if (opt->jo_env != NULL)
{ ga_init2(&ga_env, (int)sizeof(char*), 20);
ga_init2(&ga_env, (int)sizeof(char*), 20); win32_build_env(opt->jo_env, &ga_env, TRUE);
win32_build_env(opt->jo_env, &ga_env); env_wchar = ga_env.ga_data;
env_wchar = ga_env.ga_data;
}
job = job_alloc(); job = job_alloc();
if (job == NULL) if (job == NULL)
@ -3523,8 +3529,7 @@ term_and_job_init(
failed: failed:
if (argvar->v_type == VAR_LIST) if (argvar->v_type == VAR_LIST)
vim_free(ga_cmd.ga_data); vim_free(ga_cmd.ga_data);
if (opt->jo_env != NULL) vim_free(ga_env.ga_data);
vim_free(ga_env.ga_data);
vim_free(cmd_wchar); vim_free(cmd_wchar);
vim_free(cwd_wchar); vim_free(cwd_wchar);
if (spawn_config != NULL) if (spawn_config != NULL)

View File

@ -67,6 +67,7 @@ SCRIPTS_GUI =
# Tests using runtest.vim # Tests using runtest.vim
# Keep test_alot*.res as the last one, sort the others. # Keep test_alot*.res as the last one, sort the others.
# test_largefile.res is omitted, it uses too much resources to run on CI.
NEW_TESTS = test_arabic.res \ NEW_TESTS = test_arabic.res \
test_arglist.res \ test_arglist.res \
test_assert.res \ test_assert.res \
@ -78,11 +79,13 @@ NEW_TESTS = test_arabic.res \
test_cdo.res \ test_cdo.res \
test_channel.res \ test_channel.res \
test_charsearch.res \ test_charsearch.res \
test_charsearch_utf8.res \
test_cindent.res \ test_cindent.res \
test_clientserver.res \ test_clientserver.res \
test_close_count.res \ test_close_count.res \
test_cmdline.res \ test_cmdline.res \
test_command_count.res \ test_command_count.res \
test_comparators.res \
test_crypt.res \ test_crypt.res \
test_cscope.res \ test_cscope.res \
test_curswant.res \ test_curswant.res \
@ -91,13 +94,18 @@ NEW_TESTS = test_arabic.res \
test_display.res \ test_display.res \
test_edit.res \ test_edit.res \
test_erasebackword.res \ test_erasebackword.res \
test_escaped_glob.res \
test_exec_while_if.res \
test_exists.res \ test_exists.res \
test_exists_autocmd.res \
test_expr_utf8.res \
test_farsi.res \ test_farsi.res \
test_file_size.res \ test_file_size.res \
test_find_complete.res \ test_find_complete.res \
test_fixeol.res \ test_fixeol.res \
test_fnameescape.res \ test_fnameescape.res \
test_fold.res \ test_fold.res \
test_getcwd.res \
test_getvar.res \ test_getvar.res \
test_gf.res \ test_gf.res \
test_gn.res \ test_gn.res \
@ -124,8 +132,10 @@ NEW_TESTS = test_arabic.res \
test_lua.res \ test_lua.res \
test_makeencoding.res \ test_makeencoding.res \
test_man.res \ test_man.res \
test_maparg.res \
test_marks.res \ test_marks.res \
test_matchadd_conceal.res \ test_matchadd_conceal.res \
test_matchadd_conceal_utf8.res \
test_mksession.res \ test_mksession.res \
test_mksession_utf8.res \ test_mksession_utf8.res \
test_nested_function.res \ test_nested_function.res \
@ -136,6 +146,7 @@ NEW_TESTS = test_arabic.res \
test_packadd.res \ test_packadd.res \
test_paste.res \ test_paste.res \
test_perl.res \ test_perl.res \
test_plus_arg_edit.res \
test_preview.res \ test_preview.res \
test_profile.res \ test_profile.res \
test_python2.res \ test_python2.res \
@ -144,13 +155,17 @@ NEW_TESTS = test_arabic.res \
test_pyx3.res \ test_pyx3.res \
test_quickfix.res \ test_quickfix.res \
test_quotestar.res \ test_quotestar.res \
test_retab.res \ test_regex_char_classes.res \
test_regexp_latin.res \
test_regexp_utf8.res \
test_registers.res \ test_registers.res \
test_retab.res \
test_ruby.res \ test_ruby.res \
test_scrollbind.res \ test_scrollbind.res \
test_search.res \ test_search.res \
test_signs.res \ test_signs.res \
test_smartindent.res \ test_smartindent.res \
test_source_utf8.res \
test_spell.res \ test_spell.res \
test_startup.res \ test_startup.res \
test_startup_utf8.res \ test_startup_utf8.res \
@ -163,10 +178,13 @@ NEW_TESTS = test_arabic.res \
test_tcl.res \ test_tcl.res \
test_terminal.res \ test_terminal.res \
test_terminal_fail.res \ test_terminal_fail.res \
test_textformat.res \
test_textobjects.res \ test_textobjects.res \
test_undo.res \ test_undo.res \
test_usercommands.res \
test_user_func.res \ test_user_func.res \
test_usercommands.res \
test_utf8.res \
test_utf8_comparisons.res \
test_viminfo.res \ test_viminfo.res \
test_vimscript.res \ test_vimscript.res \
test_visual.res \ test_visual.res \

View File

@ -286,6 +286,10 @@ for s:test in sort(s:tests)
call add(s:messages, 'Flaky test failed, running it again') call add(s:messages, 'Flaky test failed, running it again')
let first_run = v:errors let first_run = v:errors
" Flakiness is often caused by the system being very busy. Sleep a couple
" of seconds to have a higher chance of succeeding the second time.
sleep 2
let v:errors = [] let v:errors = []
call RunTheTest(s:test) call RunTheTest(s:test)
if len(v:errors) > 0 if len(v:errors) > 0

View File

@ -9,12 +9,19 @@ function SetUp()
endfunction endfunction
function Test_glob() function Test_glob()
if !has('unix')
" This test fails on Windows because of the special characters in the
" filenames. Disable the test on non-Unix systems for now.
return
endif
call assert_equal("", glob('Xxx\{')) call assert_equal("", glob('Xxx\{'))
call assert_equal("", glob('Xxx\$')) call assert_equal("", glob('Xxx\$'))
w! Xxx{ w! Xxx{
w! Xxx\$ w! Xxx\$
call assert_equal("Xxx{", glob('Xxx\{')) call assert_equal("Xxx{", glob('Xxx\{'))
call assert_equal("Xxx$", glob('Xxx\$')) call assert_equal("Xxx$", glob('Xxx\$'))
call delete('Xxx{')
call delete('Xxx$')
endfunction endfunction
function Test_globpath() function Test_globpath()

View File

@ -5,4 +5,6 @@ function Test_edit()
edit +1|s/|/PIPE/|w Xfile1| e Xfile2|1 | s/\//SLASH/|w edit +1|s/|/PIPE/|w Xfile1| e Xfile2|1 | s/\//SLASH/|w
call assert_equal(["fooPIPEbar"], readfile("Xfile1")) call assert_equal(["fooPIPEbar"], readfile("Xfile1"))
call assert_equal(["fooSLASHbar"], readfile("Xfile2")) call assert_equal(["fooSLASHbar"], readfile("Xfile2"))
call delete('Xfile1')
call delete('Xfile2')
endfunction endfunction

View File

@ -703,4 +703,40 @@ func Test_popup_and_preview_autocommand()
bw! bw!
endfunc endfunc
func Test_balloon_split()
if !exists('*balloon_split')
return
endif
call assert_equal([
\ 'one two three four one two three four one two thre',
\ 'e four',
\ ], balloon_split(
\ 'one two three four one two three four one two three four'))
call assert_equal([
\ 'struct = {',
\ ' one = 1,',
\ ' two = 2,',
\ ' three = 3}',
\ ], balloon_split(
\ 'struct = {one = 1, two = 2, three = 3}'))
call assert_equal([
\ 'struct = {',
\ ' one = 1,',
\ ' nested = {',
\ ' n1 = "yes",',
\ ' n2 = "no"}',
\ ' two = 2}',
\ ], balloon_split(
\ 'struct = {one = 1, nested = {n1 = "yes", n2 = "no"} two = 2}'))
call assert_equal([
\ 'struct = 0x234 {',
\ ' long = 2343 "\\"some long string that will be wr',
\ 'apped in two\\"",',
\ ' next = 123}',
\ ], balloon_split(
\ 'struct = 0x234 {long = 2343 "\\"some long string that will be wrapped in two\\"", next = 123}'))
endfunc
" vim: shiftwidth=2 sts=2 expandtab " vim: shiftwidth=2 sts=2 expandtab

View File

@ -352,9 +352,7 @@ func Test_terminal_curwin()
call delete('Xtext') call delete('Xtext')
endfunc endfunc
func Test_finish_open_close() func s:get_sleep_cmd()
call assert_equal(1, winnr('$'))
if s:python != '' if s:python != ''
let cmd = s:python . " test_short_sleep.py" let cmd = s:python . " test_short_sleep.py"
let waittime = 500 let waittime = 500
@ -367,12 +365,18 @@ func Test_finish_open_close()
let cmd = 'sleep 1' let cmd = 'sleep 1'
endif endif
endif endif
return [cmd, waittime]
endfunc
func Test_terminal_finish_open_close()
call assert_equal(1, winnr('$'))
let [cmd, waittime] = s:get_sleep_cmd()
exe 'terminal ++close ' . cmd exe 'terminal ++close ' . cmd
call assert_equal(2, winnr('$')) call assert_equal(2, winnr('$'))
wincmd p wincmd p
call WaitFor("winnr('$') == 1", waittime) call WaitFor("winnr('$') == 1", waittime)
call assert_equal(1, winnr('$'))
call term_start(cmd, {'term_finish': 'close'}) call term_start(cmd, {'term_finish': 'close'})
call assert_equal(2, winnr('$')) call assert_equal(2, winnr('$'))
@ -430,6 +434,27 @@ func Test_terminal_cwd()
call delete('Xdir', 'rf') call delete('Xdir', 'rf')
endfunc endfunc
func Test_terminal_servername()
if !has('clientserver')
return
endif
let g:buf = Run_shell_in_terminal({})
" Wait for the shell to display a prompt
call WaitFor('term_getline(g:buf, 1) != ""')
if has('win32')
call term_sendkeys(g:buf, "echo %VIM_SERVERNAME%\r")
else
call term_sendkeys(g:buf, "echo $VIM_SERVERNAME\r")
endif
call term_wait(g:buf)
call Stop_shell_in_terminal(g:buf)
call WaitFor('getline(2) == v:servername')
call assert_equal(v:servername, getline(2))
exe g:buf . 'bwipe'
unlet g:buf
endfunc
func Test_terminal_env() func Test_terminal_env()
let g:buf = Run_shell_in_terminal({'env': {'TESTENV': 'correct'}}) let g:buf = Run_shell_in_terminal({'env': {'TESTENV': 'correct'}})
" Wait for the shell to display a prompt " Wait for the shell to display a prompt
@ -743,3 +768,29 @@ func Test_terminal_composing_unicode()
unlet g:job unlet g:job
let &encoding = save_enc let &encoding = save_enc
endfunc endfunc
func Test_terminal_aucmd_on_close()
fun Nop()
let s:called = 1
endfun
aug repro
au!
au BufWinLeave * call Nop()
aug END
let [cmd, waittime] = s:get_sleep_cmd()
call assert_equal(1, winnr('$'))
new
call setline(1, ['one', 'two'])
exe 'term ++close ' . cmd
wincmd p
call WaitFor("winnr('$') == 2", waittime)
call assert_equal(1, s:called)
bwipe!
unlet s:called
au! repro
delfunc Nop
endfunc

View File

@ -771,6 +771,36 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
1330,
/**/
1329,
/**/
1328,
/**/
1327,
/**/
1326,
/**/
1325,
/**/
1324,
/**/
1323,
/**/
1322,
/**/
1321,
/**/
1320,
/**/
1319,
/**/
1318,
/**/
1317,
/**/
1316,
/**/ /**/
1315, 1315,
/**/ /**/

View File

@ -1809,14 +1809,15 @@ typedef int sock_T;
/* Include option.h before structs.h, because the number of window-local and /* Include option.h before structs.h, because the number of window-local and
* buffer-local options is used there. */ * buffer-local options is used there. */
#include "option.h" /* options and default values */ #include "option.h" /* options and default values */
#include "beval.h" /* BalloonEval */
/* Note that gui.h is included by structs.h */ /* Note that gui.h is included by structs.h */
#include "structs.h" /* file that defines many structures */ #include "structs.h" /* defines many structures */
#include "alloc.h" #include "alloc.h"
#include "beval.h"
/* Values for "do_profiling". */ /* Values for "do_profiling". */
#define PROF_NONE 0 /* profiling not started */ #define PROF_NONE 0 /* profiling not started */