Mercurial > vim
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 |