@@ -766,9 +766,147 @@ static int balloon_arraysize;
766766static int balloon_mouse_row = 0 ;
767767static 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
773911ui_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