comparison src/popupwin.c @ 17431:ce35cdbe9f74 v8.1.1714

patch 8.1.1714: cannot preview a file in a popup window commit https://github.com/vim/vim/commit/7964873afe59d0896a921b7c585167674bb784d5 Author: Bram Moolenaar <Bram@vim.org> Date: Thu Jul 18 21:43:07 2019 +0200 patch 8.1.1714: cannot preview a file in a popup window Problem: Cannot preview a file in a popup window. Solution: Add the 'previewpopup' option.
author Bram Moolenaar <Bram@vim.org>
date Thu, 18 Jul 2019 21:45:06 +0200
parents 6e756ad5ef1a
children a5874fdc8f3a
comparison
equal deleted inserted replaced
17430:23c5d343007c 17431:ce35cdbe9f74
11 * Implementation of popup windows. See ":help popup". 11 * Implementation of popup windows. See ":help popup".
12 */ 12 */
13 13
14 #include "vim.h" 14 #include "vim.h"
15 15
16 #ifdef FEAT_TEXT_PROP 16 #if defined(FEAT_TEXT_PROP) || defined(PROTO)
17 17
18 typedef struct { 18 typedef struct {
19 char *pp_name; 19 char *pp_name;
20 poppos_T pp_val; 20 poppos_T pp_val;
21 } poppos_entry_T; 21 } poppos_entry_T;
440 } 440 }
441 } 441 }
442 } 442 }
443 443
444 /* 444 /*
445 * Scroll to show the line with the cursor. This assumes lines don't wrap.
446 */
447 static void
448 popup_show_curline(win_T *wp)
449 {
450 if (wp->w_cursor.lnum < wp->w_topline)
451 wp->w_topline = wp->w_cursor.lnum;
452 else if (wp->w_cursor.lnum >= wp->w_botline)
453 wp->w_topline = wp->w_cursor.lnum - wp->w_height + 1;
454 }
455
456 /*
445 * Highlight the line with the cursor. 457 * Highlight the line with the cursor.
446 * Also scrolls the text to put the cursor line in view. 458 * Also scrolls the text to put the cursor line in view.
447 */ 459 */
448 static void 460 static void
449 popup_highlight_curline(win_T *wp) 461 popup_highlight_curline(win_T *wp)
453 465
454 match_delete(wp, 1, FALSE); 466 match_delete(wp, 1, FALSE);
455 467
456 if ((wp->w_popup_flags & POPF_CURSORLINE) != 0) 468 if ((wp->w_popup_flags & POPF_CURSORLINE) != 0)
457 { 469 {
458 // Scroll to show the line with the cursor. This assumes lines don't 470 popup_show_curline(wp);
459 // wrap.
460 while (wp->w_topline + wp->w_height - 1 < wp->w_cursor.lnum)
461 wp->w_topline++;
462 while (wp->w_cursor.lnum < wp->w_topline)
463 wp->w_topline--;
464 471
465 id = syn_name2id((char_u *)"PopupSelected"); 472 id = syn_name2id((char_u *)"PopupSelected");
466 vim_snprintf(buf, sizeof(buf), "\\%%%dl.*", (int)wp->w_cursor.lnum); 473 vim_snprintf(buf, sizeof(buf), "\\%%%dl.*", (int)wp->w_cursor.lnum);
467 match_add(wp, (char_u *)(id == 0 ? "PmenuSel" : "PopupSelected"), 474 match_add(wp, (char_u *)(id == 0 ? "PmenuSel" : "PopupSelected"),
468 (char_u *)buf, 10, 1, NULL, NULL); 475 (char_u *)buf, 10, 1, NULL, NULL);
921 allow_adjust_left = FALSE; 928 allow_adjust_left = FALSE;
922 maxwidth = wp->w_maxwidth; 929 maxwidth = wp->w_maxwidth;
923 } 930 }
924 931
925 // start at the desired first line 932 // start at the desired first line
926 wp->w_topline = wp->w_firstline; 933 if (wp->w_firstline != 0)
934 wp->w_topline = wp->w_firstline;
927 if (wp->w_topline > wp->w_buffer->b_ml.ml_line_count) 935 if (wp->w_topline > wp->w_buffer->b_ml.ml_line_count)
928 wp->w_topline = wp->w_buffer->b_ml.ml_line_count; 936 wp->w_topline = wp->w_buffer->b_ml.ml_line_count;
929 937
930 // Compute width based on longest text line and the 'wrap' option. 938 // Compute width based on longest text line and the 'wrap' option.
931 // Use a minimum width of one, so that something shows when there is no 939 // Use a minimum width of one, so that something shows when there is no
1076 TYPE_NORMAL, 1084 TYPE_NORMAL,
1077 TYPE_ATCURSOR, 1085 TYPE_ATCURSOR,
1078 TYPE_BEVAL, 1086 TYPE_BEVAL,
1079 TYPE_NOTIFICATION, 1087 TYPE_NOTIFICATION,
1080 TYPE_DIALOG, 1088 TYPE_DIALOG,
1081 TYPE_MENU 1089 TYPE_MENU,
1090 TYPE_PREVIEW
1082 } create_type_T; 1091 } create_type_T;
1083 1092
1084 /* 1093 /*
1085 * Make "buf" empty and set the contents to "text". 1094 * Make "buf" empty and set the contents to "text".
1086 * Used by popup_create() and popup_settext(). 1095 * Used by popup_create() and popup_settext().
1122 ml_delete(buf->b_ml.ml_line_count, FALSE); 1131 ml_delete(buf->b_ml.ml_line_count, FALSE);
1123 curbuf = curwin->w_buffer; 1132 curbuf = curwin->w_buffer;
1124 } 1133 }
1125 1134
1126 /* 1135 /*
1136 * Parse the 'previewpopup' option and apply the values to window "wp" if it
1137 * not NULL.
1138 * Return FAIL if the parsing fails.
1139 */
1140 int
1141 parse_previewpopup(win_T *wp)
1142 {
1143 char_u *p;
1144
1145 for (p = p_pvp; *p != NUL; p += (*p == ',' ? 1 : 0))
1146 {
1147 char_u *e, *dig;
1148 char_u *s = p;
1149 int x;
1150
1151 e = vim_strchr(p, ':');
1152 if (e == NULL || e[1] == NUL)
1153 return FAIL;
1154
1155 p = vim_strchr(e, ',');
1156 if (p == NULL)
1157 p = e + STRLEN(e);
1158 dig = e + 1;
1159 x = getdigits(&dig);
1160 if (dig != p)
1161 return FAIL;
1162
1163 if (STRNCMP(s, "height:", 7) == 0)
1164 {
1165 if (wp != NULL)
1166 {
1167 wp->w_minheight = x;
1168 wp->w_maxheight = x;
1169 }
1170 }
1171 else if (STRNCMP(s, "width:", 6) == 0)
1172 {
1173 if (wp != NULL)
1174 {
1175 wp->w_minwidth = x;
1176 wp->w_maxwidth = x;
1177 }
1178 }
1179 else
1180 return FAIL;
1181 }
1182 return OK;
1183 }
1184
1185 /*
1186 * Set w_wantline and w_wantcol for the cursor position in the current window.
1187 */
1188 void
1189 popup_set_wantpos(win_T *wp)
1190 {
1191 setcursor_mayforce(TRUE);
1192 wp->w_wantline = curwin->w_winrow + curwin->w_wrow;
1193 if (wp->w_wantline == 0) // cursor in first line
1194 {
1195 wp->w_wantline = 2;
1196 wp->w_popup_pos = POPPOS_TOPLEFT;
1197 }
1198 wp->w_wantcol = curwin->w_wincol + curwin->w_wcol + 1;
1199 popup_adjust_position(wp);
1200 }
1201
1202 /*
1127 * popup_create({text}, {options}) 1203 * popup_create({text}, {options})
1128 * popup_atcursor({text}, {options}) 1204 * popup_atcursor({text}, {options})
1205 * etc.
1206 * When creating a preview window popup "argvars" and "rettv" are NULL.
1129 */ 1207 */
1130 static win_T * 1208 static win_T *
1131 popup_create(typval_T *argvars, typval_T *rettv, create_type_T type) 1209 popup_create(typval_T *argvars, typval_T *rettv, create_type_T type)
1132 { 1210 {
1133 win_T *wp; 1211 win_T *wp;
1134 tabpage_T *tp = NULL; 1212 tabpage_T *tp = NULL;
1135 int tabnr; 1213 int tabnr = 0;
1136 int new_buffer; 1214 int new_buffer;
1137 buf_T *buf = NULL; 1215 buf_T *buf = NULL;
1138 dict_T *d; 1216 dict_T *d = NULL;
1139 int nr; 1217 int nr;
1140 int i; 1218 int i;
1141 1219
1142 // Check arguments look OK. 1220 if (argvars != NULL)
1143 if (argvars[0].v_type == VAR_NUMBER) 1221 {
1144 { 1222 // Check arguments look OK.
1145 buf = buflist_findnr( argvars[0].vval.v_number); 1223 if (argvars[0].v_type == VAR_NUMBER)
1146 if (buf == NULL) 1224 {
1147 { 1225 buf = buflist_findnr( argvars[0].vval.v_number);
1148 semsg(_(e_nobufnr), argvars[0].vval.v_number); 1226 if (buf == NULL)
1227 {
1228 semsg(_(e_nobufnr), argvars[0].vval.v_number);
1229 return NULL;
1230 }
1231 }
1232 else if (!(argvars[0].v_type == VAR_STRING
1233 && argvars[0].vval.v_string != NULL)
1234 && !(argvars[0].v_type == VAR_LIST
1235 && argvars[0].vval.v_list != NULL))
1236 {
1237 emsg(_(e_listreq));
1149 return NULL; 1238 return NULL;
1150 } 1239 }
1151 } 1240 if (argvars[1].v_type != VAR_DICT || argvars[1].vval.v_dict == NULL)
1152 else if (!(argvars[0].v_type == VAR_STRING 1241 {
1153 && argvars[0].vval.v_string != NULL) 1242 emsg(_(e_dictreq));
1154 && !(argvars[0].v_type == VAR_LIST
1155 && argvars[0].vval.v_list != NULL))
1156 {
1157 emsg(_(e_listreq));
1158 return NULL;
1159 }
1160 if (argvars[1].v_type != VAR_DICT || argvars[1].vval.v_dict == NULL)
1161 {
1162 emsg(_(e_dictreq));
1163 return NULL;
1164 }
1165 d = argvars[1].vval.v_dict;
1166
1167 if (dict_find(d, (char_u *)"tabpage", -1) != NULL)
1168 tabnr = (int)dict_get_number(d, (char_u *)"tabpage");
1169 else if (type == TYPE_NOTIFICATION)
1170 tabnr = -1; // notifications are global by default
1171 else
1172 tabnr = 0;
1173 if (tabnr > 0)
1174 {
1175 tp = find_tabpage(tabnr);
1176 if (tp == NULL)
1177 {
1178 semsg(_("E997: Tabpage not found: %d"), tabnr);
1179 return NULL; 1243 return NULL;
1244 }
1245 d = argvars[1].vval.v_dict;
1246 }
1247
1248 if (d != NULL)
1249 {
1250 if (dict_find(d, (char_u *)"tabpage", -1) != NULL)
1251 tabnr = (int)dict_get_number(d, (char_u *)"tabpage");
1252 else if (type == TYPE_NOTIFICATION)
1253 tabnr = -1; // notifications are global by default
1254 else
1255 tabnr = 0;
1256 if (tabnr > 0)
1257 {
1258 tp = find_tabpage(tabnr);
1259 if (tp == NULL)
1260 {
1261 semsg(_("E997: Tabpage not found: %d"), tabnr);
1262 return NULL;
1263 }
1180 } 1264 }
1181 } 1265 }
1182 1266
1183 // Create the window and buffer. 1267 // Create the window and buffer.
1184 wp = win_alloc_popup_win(); 1268 wp = win_alloc_popup_win();
1185 if (wp == NULL) 1269 if (wp == NULL)
1186 return NULL; 1270 return NULL;
1187 rettv->vval.v_number = wp->w_id; 1271 if (rettv != NULL)
1272 rettv->vval.v_number = wp->w_id;
1188 wp->w_popup_pos = POPPOS_TOPLEFT; 1273 wp->w_popup_pos = POPPOS_TOPLEFT;
1189 wp->w_popup_flags = POPF_IS_POPUP; 1274 wp->w_popup_flags = POPF_IS_POPUP;
1190 1275
1191 if (buf != NULL) 1276 if (buf != NULL)
1192 { 1277 {
1209 1294
1210 set_local_options_default(wp); 1295 set_local_options_default(wp);
1211 set_string_option_direct_in_buf(buf, (char_u *)"buftype", -1, 1296 set_string_option_direct_in_buf(buf, (char_u *)"buftype", -1,
1212 (char_u *)"popup", OPT_FREE|OPT_LOCAL, 0); 1297 (char_u *)"popup", OPT_FREE|OPT_LOCAL, 0);
1213 set_string_option_direct_in_buf(buf, (char_u *)"bufhidden", -1, 1298 set_string_option_direct_in_buf(buf, (char_u *)"bufhidden", -1,
1214 (char_u *)"hide", OPT_FREE|OPT_LOCAL, 0); 1299 (char_u *)"wipe", OPT_FREE|OPT_LOCAL, 0);
1215 buf->b_p_ul = -1; // no undo 1300 buf->b_p_ul = -1; // no undo
1216 buf->b_p_swf = FALSE; // no swap file 1301 buf->b_p_swf = FALSE; // no swap file
1217 buf->b_p_bl = FALSE; // unlisted buffer 1302 buf->b_p_bl = FALSE; // unlisted buffer
1218 buf->b_locked = TRUE; 1303 buf->b_locked = TRUE;
1219 wp->w_p_wrap = TRUE; // 'wrap' is default on 1304 wp->w_p_wrap = TRUE; // 'wrap' is default on
1248 prev = prev->w_next; 1333 prev = prev->w_next;
1249 prev->w_next = wp; 1334 prev->w_next = wp;
1250 } 1335 }
1251 } 1336 }
1252 1337
1253 if (new_buffer) 1338 if (new_buffer && argvars != NULL)
1254 popup_set_buffer_text(buf, argvars[0]); 1339 popup_set_buffer_text(buf, argvars[0]);
1255 1340
1341 if (type == TYPE_ATCURSOR || type == TYPE_PREVIEW)
1342 {
1343 wp->w_popup_pos = POPPOS_BOTLEFT;
1344 popup_set_wantpos(wp);
1345 }
1256 if (type == TYPE_ATCURSOR) 1346 if (type == TYPE_ATCURSOR)
1257 { 1347 {
1258 wp->w_popup_pos = POPPOS_BOTLEFT;
1259 setcursor_mayforce(TRUE);
1260 wp->w_wantline = curwin->w_winrow + curwin->w_wrow;
1261 if (wp->w_wantline == 0) // cursor in first line
1262 {
1263 wp->w_wantline = 2;
1264 wp->w_popup_pos = POPPOS_TOPLEFT;
1265 }
1266 wp->w_wantcol = curwin->w_wincol + curwin->w_wcol + 1;
1267 set_moved_values(wp); 1348 set_moved_values(wp);
1268 set_moved_columns(wp, FIND_STRING); 1349 set_moved_columns(wp, FIND_STRING);
1269 } 1350 }
1270 1351
1271 if (type == TYPE_BEVAL) 1352 if (type == TYPE_BEVAL)
1358 1439
1359 wp->w_p_wrap = 0; 1440 wp->w_p_wrap = 0;
1360 wp->w_popup_flags |= POPF_CURSORLINE; 1441 wp->w_popup_flags |= POPF_CURSORLINE;
1361 } 1442 }
1362 1443
1444 if (type == TYPE_PREVIEW)
1445 {
1446 wp->w_popup_drag = 1;
1447 wp->w_popup_close = POPCLOSE_BUTTON;
1448 for (i = 0; i < 4; ++i)
1449 wp->w_popup_border[i] = 1;
1450 parse_previewpopup(wp);
1451 }
1452
1363 for (i = 0; i < 4; ++i) 1453 for (i = 0; i < 4; ++i)
1364 VIM_CLEAR(wp->w_border_highlight[i]); 1454 VIM_CLEAR(wp->w_border_highlight[i]);
1365 for (i = 0; i < 8; ++i) 1455 for (i = 0; i < 8; ++i)
1366 wp->w_border_char[i] = 0; 1456 wp->w_border_char[i] = 0;
1367 wp->w_want_scrollbar = 1; 1457 wp->w_want_scrollbar = 1;
1368 wp->w_popup_fixed = 0; 1458 wp->w_popup_fixed = 0;
1369 1459
1370 // Deal with options. 1460 if (d != NULL)
1371 apply_options(wp, argvars[1].vval.v_dict); 1461 // Deal with options.
1462 apply_options(wp, d);
1372 1463
1373 #ifdef FEAT_TIMERS 1464 #ifdef FEAT_TIMERS
1374 if (type == TYPE_NOTIFICATION && wp->w_popup_timer == NULL) 1465 if (type == TYPE_NOTIFICATION && wp->w_popup_timer == NULL)
1375 popup_add_timeout(wp, 3000); 1466 popup_add_timeout(wp, 3000);
1376 #endif 1467 #endif
2837 if (abort) 2928 if (abort)
2838 break; 2929 break;
2839 } 2930 }
2840 return abort; 2931 return abort;
2841 } 2932 }
2933
2934 /*
2935 * Find an existing popup used as the preview window, in the current tab page.
2936 * Return NULL if not found.
2937 */
2938 win_T *
2939 popup_find_preview_window(void)
2940 {
2941 win_T *wp;
2942
2943 // Preview window popup is always local to tab page.
2944 for (wp = curtab->tp_first_popupwin; wp != NULL; wp = wp->w_next)
2945 if (wp->w_p_pvw)
2946 return wp;
2947 return wp;
2948 }
2949
2950 int
2951 popup_is_popup(win_T *wp)
2952 {
2953 return wp->w_popup_flags != 0;
2954 }
2955
2956 /*
2957 * Create a popup to be used as the preview window.
2958 * NOTE: this makes the popup the current window, so that the file can be
2959 * edited. However, it must not remain to be the current window, the caller
2960 * must make sure of that.
2961 */
2962 int
2963 popup_create_preview_window(void)
2964 {
2965 win_T *wp = popup_create(NULL, NULL, TYPE_PREVIEW);
2966
2967 if (wp == NULL)
2968 return FAIL;
2969 wp->w_p_pvw = TRUE;
2970
2971 // Set the width to a reasonable value, so that w_topline can be computed.
2972 if (wp->w_minwidth > 0)
2973 wp->w_width = wp->w_minwidth;
2974 else if (wp->w_maxwidth > 0)
2975 wp->w_width = wp->w_maxwidth;
2976 else
2977 wp->w_width = curwin->w_width;
2978
2979 // Will switch to another buffer soon, dummy one can be wiped.
2980 wp->w_buffer->b_locked = FALSE;
2981
2982 win_enter(wp, FALSE);
2983 return OK;
2984 }
2985
2986 void
2987 popup_close_preview()
2988 {
2989 win_T *wp = popup_find_preview_window();
2990
2991 if (wp != NULL)
2992 {
2993 typval_T res;
2994
2995 res.v_type = VAR_NUMBER;
2996 res.vval.v_number = -1;
2997 popup_close_and_callback(wp, &res);
2998 }
2999 }
3000
2842 #endif // FEAT_TEXT_PROP 3001 #endif // FEAT_TEXT_PROP