Skip to content

Commit c8a233b

Browse files
committed
Merge remote-tracking branch 'vim/master'
2 parents 6023f13 + 5bbef31 commit c8a233b

14 files changed

Lines changed: 298 additions & 32 deletions

File tree

runtime/doc/eval.txt

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2032,6 +2032,7 @@ asin({expr}) Float arc sine of {expr}
20322032
atan({expr}) Float arc tangent of {expr}
20332033
atan2({expr1}, {expr2}) Float arc tangent of {expr1} / {expr2}
20342034
balloon_show({msg}) none show {msg} inside the balloon
2035+
balloon_split({msg}) List split {msg} as used for a balloon
20352036
browse({save}, {title}, {initdir}, {default})
20362037
String put up a file requester
20372038
browsedir({title}, {initdir}) String put up a directory requester
@@ -2682,8 +2683,12 @@ atan2({expr1}, {expr2}) *atan2()*
26822683
< 2.356194
26832684
{only available when compiled with the |+float| feature}
26842685

2685-
balloon_show({msg}) *balloon_show()*
2686-
Show {msg} inside the balloon.
2686+
balloon_show({expr}) *balloon_show()*
2687+
Show {expr} inside the balloon. For the GUI {expr} is used as
2688+
a string. For a terminal {expr} can be a list, which contains
2689+
the lines of the balloon. If {expr} is not a list it will be
2690+
split with |balloon_split()|.
2691+
26872692
Example: >
26882693
func GetBalloonContent()
26892694
" initiate getting the content
@@ -2703,7 +2708,16 @@ balloon_show({msg}) *balloon_show()*
27032708

27042709
When showing a balloon is not possible nothing happens, no
27052710
error message.
2706-
{only available when compiled with the +balloon_eval feature}
2711+
{only available when compiled with the +balloon_eval or
2712+
+balloon_eval_term feature}
2713+
2714+
balloon_split({msg}) *balloon_split()*
2715+
Split {msg} into lines to be displayed in a balloon. The
2716+
splits are made for the current window size and optimize to
2717+
show debugger output.
2718+
Returns a |List| with the split lines.
2719+
{only available when compiled with the +balloon_eval_term
2720+
feature}
27072721

27082722
*browse()*
27092723
browse({save}, {title}, {initdir}, {default})

runtime/pack/dist/opt/termdebug/plugin/termdebug.vim

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -127,9 +127,11 @@ func s:StartDebug(cmd)
127127
call win_gotoid(s:gdbwin)
128128

129129
" Enable showing a balloon with eval info
130-
if has("balloon_eval")
131-
set ballooneval
130+
if has("balloon_eval") || has("balloon_eval_term")
132131
set balloonexpr=TermDebugBalloonExpr()
132+
if has("balloon_eval")
133+
set ballooneval
134+
endif
133135
if has("balloon_eval_term")
134136
set balloonevalterm
135137
endif
@@ -158,9 +160,11 @@ func s:EndDebug(job, status)
158160
let &columns = s:save_columns
159161
endif
160162

161-
if has("balloon_eval")
162-
set noballooneval
163+
if has("balloon_eval") || has("balloon_eval_term")
163164
set balloonexpr=
165+
if has("balloon_eval")
166+
set noballooneval
167+
endif
164168
if has("balloon_eval_term")
165169
set noballoonevalterm
166170
endif
@@ -366,6 +370,7 @@ func s:HandleError(msg)
366370
if a:msg =~ 'No symbol .* in current context'
367371
\ || a:msg =~ 'Cannot access memory at address '
368372
\ || a:msg =~ 'Attempt to use a type name as an expression'
373+
\ || a:msg =~ 'A syntax error in expression,'
369374
" Result of s:SendEval() failed, ignore.
370375
return
371376
endif

src/beval.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -134,19 +134,20 @@ get_beval_info(
134134
}
135135

136136
/*
137-
* Show a balloon with "mesg".
137+
* Show a balloon with "mesg" or "list".
138138
*/
139139
void
140-
post_balloon(BalloonEval *beval UNUSED, char_u *mesg)
140+
post_balloon(BalloonEval *beval UNUSED, char_u *mesg, list_T *list)
141141
{
142142
# ifdef FEAT_BEVAL_TERM
143143
# ifdef FEAT_GUI
144144
if (!gui.in_use)
145145
# endif
146-
ui_post_balloon(mesg);
146+
ui_post_balloon(mesg, list);
147147
# endif
148148
# ifdef FEAT_BEVAL_GUI
149149
if (gui.in_use)
150+
/* GUI can't handle a list */
150151
gui_mch_post_balloon(beval, mesg);
151152
# endif
152153
}
@@ -257,7 +258,7 @@ general_beval_cb(BalloonEval *beval, int state UNUSED)
257258
set_vim_var_string(VV_BEVAL_TEXT, NULL, -1);
258259
if (result != NULL && result[0] != NUL)
259260
{
260-
post_balloon(beval, result);
261+
post_balloon(beval, result, NULL);
261262
recursive = FALSE;
262263
return;
263264
}

src/beval.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,6 @@ typedef struct BalloonEvalStruct
8282
#define EVAL_OFFSET_X 15 /* displacement of beval topleft corner from pointer */
8383
#define EVAL_OFFSET_Y 10
8484

85-
#include "beval.pro"
8685
#ifdef FEAT_BEVAL_GUI
8786
# include "gui_beval.pro"
8887
#endif

src/evalfunc.c

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,9 @@ static void f_atan2(typval_T *argvars, typval_T *rettv);
6161
#endif
6262
#ifdef FEAT_BEVAL
6363
static void f_balloon_show(typval_T *argvars, typval_T *rettv);
64+
# if defined(FEAT_BEVAL_TERM)
65+
static void f_balloon_split(typval_T *argvars, typval_T *rettv);
66+
# endif
6467
#endif
6568
static void f_browse(typval_T *argvars, typval_T *rettv);
6669
static void f_browsedir(typval_T *argvars, typval_T *rettv);
@@ -494,6 +497,9 @@ static struct fst
494497
#endif
495498
#ifdef FEAT_BEVAL
496499
{"balloon_show", 1, 1, f_balloon_show},
500+
# if defined(FEAT_BEVAL_TERM)
501+
{"balloon_split", 1, 1, f_balloon_split},
502+
# endif
497503
#endif
498504
{"browse", 4, 4, f_browse},
499505
{"browsedir", 2, 2, f_browsedir},
@@ -1410,8 +1416,40 @@ f_atan2(typval_T *argvars, typval_T *rettv)
14101416
f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
14111417
{
14121418
if (balloonEval != NULL)
1413-
post_balloon(balloonEval, get_tv_string_chk(&argvars[0]));
1419+
{
1420+
if (argvars[0].v_type == VAR_LIST
1421+
# ifdef FEAT_GUI
1422+
&& !gui.in_use
1423+
# endif
1424+
)
1425+
post_balloon(balloonEval, NULL, argvars[0].vval.v_list);
1426+
else
1427+
post_balloon(balloonEval, get_tv_string_chk(&argvars[0]), NULL);
1428+
}
1429+
}
1430+
1431+
# if defined(FEAT_BEVAL_TERM)
1432+
static void
1433+
f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1434+
{
1435+
if (rettv_list_alloc(rettv) == OK)
1436+
{
1437+
char_u *msg = get_tv_string_chk(&argvars[0]);
1438+
1439+
if (msg != NULL)
1440+
{
1441+
pumitem_T *array;
1442+
int size = split_message(msg, &array);
1443+
int i;
1444+
1445+
/* Skip the first and last item, they are always empty. */
1446+
for (i = 1; i < size - 1; ++i)
1447+
list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
1448+
vim_free(array);
1449+
}
1450+
}
14141451
}
1452+
# endif
14151453
#endif
14161454

14171455
/*

src/popupmnu.c

Lines changed: 165 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -766,9 +766,147 @@ static int balloon_arraysize;
766766
static int balloon_mouse_row = 0;
767767
static int balloon_mouse_col = 0;
768768

769-
#define BALLOON_MIN_WIDTH 40
769+
#define BALLOON_MIN_WIDTH 50
770770
#define BALLOON_MIN_HEIGHT 10
771771

772+
typedef struct {
773+
char_u *start;
774+
int bytelen;
775+
int cells;
776+
int indent;
777+
} balpart_T;
778+
779+
/*
780+
* Split a string into parts to display in the balloon.
781+
* Aimed at output from gdb. Attempts to split at white space, preserve quoted
782+
* strings and make a struct look good.
783+
* Resulting array is stored in "array" and returns the size of the array.
784+
*/
785+
int
786+
split_message(char_u *mesg, pumitem_T **array)
787+
{
788+
garray_T ga;
789+
char_u *p;
790+
balpart_T *item;
791+
int quoted = FALSE;
792+
int height;
793+
int line;
794+
int item_idx;
795+
int indent = 0;
796+
int max_cells = 0;
797+
int max_height = Rows / 2 - 2;
798+
int long_item_count = 0;
799+
int split_long_items = FALSE;
800+
801+
ga_init2(&ga, sizeof(balpart_T), 20);
802+
p = mesg;
803+
804+
while (*p != NUL)
805+
{
806+
if (ga_grow(&ga, 1) == FAIL)
807+
goto failed;
808+
item = ((balpart_T *)ga.ga_data) + ga.ga_len;
809+
item->start = p;
810+
item->indent = indent;
811+
item->cells = indent * 2;
812+
++ga.ga_len;
813+
while (*p != NUL)
814+
{
815+
if (*p == '"')
816+
quoted = !quoted;
817+
else if (*p == '\\' && p[1] != NUL)
818+
++p;
819+
else if (!quoted)
820+
{
821+
if ((*p == ',' && p[1] == ' ') || *p == '{' || *p == '}')
822+
{
823+
/* Looks like a good point to break. */
824+
if (*p == '{')
825+
++indent;
826+
else if (*p == '}' && indent > 0)
827+
--indent;
828+
++item->cells;
829+
p = skipwhite(p + 1);
830+
break;
831+
}
832+
}
833+
item->cells += ptr2cells(p);
834+
p += MB_PTR2LEN(p);
835+
}
836+
item->bytelen = p - item->start;
837+
if (item->cells > max_cells)
838+
max_cells = item->cells;
839+
long_item_count += item->cells / BALLOON_MIN_WIDTH;
840+
}
841+
842+
height = 2 + ga.ga_len;
843+
844+
/* If there are long items and the height is below the limit: split lines */
845+
if (long_item_count > 0 && height + long_item_count <= max_height)
846+
{
847+
split_long_items = TRUE;
848+
height += long_item_count;
849+
}
850+
851+
/* Limit to half the window height, it has to fit above or below the mouse
852+
* position. */
853+
if (height > max_height)
854+
height = max_height;
855+
*array = (pumitem_T *)alloc_clear((unsigned)sizeof(pumitem_T) * height);
856+
if (*array == NULL)
857+
goto failed;
858+
859+
/* Add an empty line above and below, looks better. */
860+
(*array)->pum_text = vim_strsave((char_u *)"");
861+
(*array + height - 1)->pum_text = vim_strsave((char_u *)"");
862+
863+
for (line = 1, item_idx = 0; line < height - 1; ++item_idx)
864+
{
865+
int skip;
866+
int thislen;
867+
int copylen;
868+
int ind;
869+
int cells;
870+
871+
item = ((balpart_T *)ga.ga_data) + item_idx;
872+
for (skip = 0; skip < item->bytelen; skip += thislen)
873+
{
874+
if (split_long_items && item->cells >= BALLOON_MIN_WIDTH)
875+
{
876+
cells = item->indent * 2;
877+
for (p = item->start + skip; p < item->start + item->bytelen;
878+
p += MB_PTR2LEN(p))
879+
if ((cells += ptr2cells(p)) > BALLOON_MIN_WIDTH)
880+
break;
881+
thislen = p - (item->start + skip);
882+
}
883+
else
884+
thislen = item->bytelen;
885+
886+
/* put indent at the start */
887+
p = alloc(thislen + item->indent * 2 + 1);
888+
for (ind = 0; ind < item->indent * 2; ++ind)
889+
p[ind] = ' ';
890+
891+
/* exclude spaces at the end of the string */
892+
for (copylen = thislen; copylen > 0; --copylen)
893+
if (item->start[skip + copylen - 1] != ' ')
894+
break;
895+
896+
vim_strncpy(p + ind, item->start + skip, copylen);
897+
(*array)[line].pum_text = p;
898+
item->indent = 0; /* wrapped line has no indent */
899+
++line;
900+
}
901+
}
902+
ga_clear(&ga);
903+
return height;
904+
905+
failed:
906+
ga_clear(&ga);
907+
return 0;
908+
}
909+
772910
void
773911
ui_remove_balloon(void)
774912
{
@@ -786,28 +924,42 @@ ui_remove_balloon(void)
786924
* Terminal version of a balloon, uses the popup menu code.
787925
*/
788926
void
789-
ui_post_balloon(char_u *mesg)
927+
ui_post_balloon(char_u *mesg, list_T *list)
790928
{
791929
ui_remove_balloon();
792930

793-
/* TODO: split the text in multiple lines. */
794-
balloon_arraysize = 3;
795-
balloon_array = (pumitem_T *)alloc_clear(
796-
(unsigned)sizeof(pumitem_T) * balloon_arraysize);
797-
if (balloon_array != NULL)
931+
if (mesg == NULL && list == NULL)
932+
return;
933+
if (list != NULL)
798934
{
799-
/* Add an empty line above and below, looks better. */
800-
balloon_array[0].pum_text = vim_strsave((char_u *)"");
801-
balloon_array[1].pum_text = vim_strsave(mesg);
802-
balloon_array[2].pum_text = vim_strsave((char_u *)"");
935+
listitem_T *li;
936+
int idx;
937+
938+
balloon_arraysize = list->lv_len;
939+
balloon_array = (pumitem_T *)alloc_clear(
940+
(unsigned)sizeof(pumitem_T) * list->lv_len);
941+
if (balloon_array == NULL)
942+
return;
943+
for (idx = 0, li = list->lv_first; li != NULL; li = li->li_next, ++idx)
944+
{
945+
char_u *text = get_tv_string_chk(&li->li_tv);
803946

947+
balloon_array[idx].pum_text = vim_strsave(
948+
text == NULL ? (char_u *)"" : text);
949+
}
950+
}
951+
else
952+
balloon_arraysize = split_message(mesg, &balloon_array);
953+
954+
if (balloon_arraysize > 0)
955+
{
804956
pum_array = balloon_array;
805957
pum_size = balloon_arraysize;
806958
pum_compute_size();
807959
pum_scrollbar = 0;
808960
pum_height = balloon_arraysize;
809961

810-
if (Rows - mouse_row > BALLOON_MIN_HEIGHT)
962+
if (Rows - mouse_row > pum_size)
811963
{
812964
/* Enough space below the mouse row. */
813965
pum_row = mouse_row + 1;
@@ -817,7 +969,7 @@ ui_post_balloon(char_u *mesg)
817969
else
818970
{
819971
/* Show above the mouse row, reduce height if it does not fit. */
820-
pum_row = mouse_row - 1 - pum_size;
972+
pum_row = mouse_row - pum_size;
821973
if (pum_row < 0)
822974
{
823975
pum_height += pum_row;

0 commit comments

Comments
 (0)