1 /* vi:set ts=8 sts=4 sw=4 noet: 2 * 3 * VIM - Vi IMproved by Bram Moolenaar 4 * Visual Workshop integration by Gordon Prieur 5 * 6 * Do ":help uganda" in Vim to read copying and usage conditions. 7 * Do ":help credits" in Vim to see a list of people who contributed. 8 * See README.txt for an overview of the Vim source code. 9 */ 10 11 #include "vim.h" 12 13 #if defined(FEAT_BEVAL) || defined(PROTO) 14 15 /* 16 * Get the text and position to be evaluated for "beval". 17 * If "getword" is true the returned text is not the whole line but the 18 * relevant word in allocated memory. 19 * Returns OK or FAIL. 20 */ 21 int 22 get_beval_info( 23 BalloonEval *beval, 24 int getword, 25 win_T **winp, 26 linenr_T *lnump, 27 char_u **textp, 28 int *colp) 29 { 30 win_T *wp; 31 int row, col; 32 char_u *lbuf; 33 linenr_T lnum; 34 35 *textp = NULL; 36 # ifdef FEAT_BEVAL_TERM 37 # ifdef FEAT_GUI 38 if (!gui.in_use) 39 # endif 40 { 41 row = mouse_row; 42 col = mouse_col; 43 } 44 # endif 45 # ifdef FEAT_GUI 46 if (gui.in_use) 47 { 48 row = Y_2_ROW(beval->y); 49 col = X_2_COL(beval->x); 50 } 51 #endif 52 wp = mouse_find_win(&row, &col); 53 if (wp != NULL && row >= 0 && row < wp->w_height && col < wp->w_width) 54 { 55 /* Found a window and the cursor is in the text. Now find the line 56 * number. */ 57 if (!mouse_comp_pos(wp, &row, &col, &lnum)) 58 { 59 /* Not past end of the file. */ 60 lbuf = ml_get_buf(wp->w_buffer, lnum, FALSE); 61 if (col <= win_linetabsize(wp, lbuf, (colnr_T)MAXCOL)) 62 { 63 /* Not past end of line. */ 64 if (getword) 65 { 66 /* For Netbeans we get the relevant part of the line 67 * instead of the whole line. */ 68 int len; 69 pos_T *spos = NULL, *epos = NULL; 70 71 if (VIsual_active) 72 { 73 if (LT_POS(VIsual, curwin->w_cursor)) 74 { 75 spos = &VIsual; 76 epos = &curwin->w_cursor; 77 } 78 else 79 { 80 spos = &curwin->w_cursor; 81 epos = &VIsual; 82 } 83 } 84 85 col = vcol2col(wp, lnum, col); 86 87 if (VIsual_active 88 && wp->w_buffer == curwin->w_buffer 89 && (lnum == spos->lnum 90 ? col >= (int)spos->col 91 : lnum > spos->lnum) 92 && (lnum == epos->lnum 93 ? col <= (int)epos->col 94 : lnum < epos->lnum)) 95 { 96 /* Visual mode and pointing to the line with the 97 * Visual selection: return selected text, with a 98 * maximum of one line. */ 99 if (spos->lnum != epos->lnum || spos->col == epos->col) 100 return FAIL; 101 102 lbuf = ml_get_buf(curwin->w_buffer, VIsual.lnum, FALSE); 103 len = epos->col - spos->col; 104 if (*p_sel != 'e') 105 len += MB_PTR2LEN(lbuf + epos->col); 106 lbuf = vim_strnsave(lbuf + spos->col, len); 107 lnum = spos->lnum; 108 col = spos->col; 109 } 110 else 111 { 112 /* Find the word under the cursor. */ 113 ++emsg_off; 114 len = find_ident_at_pos(wp, lnum, (colnr_T)col, &lbuf, 115 FIND_IDENT + FIND_STRING + FIND_EVAL); 116 --emsg_off; 117 if (len == 0) 118 return FAIL; 119 lbuf = vim_strnsave(lbuf, len); 120 } 121 } 122 123 *winp = wp; 124 *lnump = lnum; 125 *textp = lbuf; 126 *colp = col; 127 #ifdef FEAT_VARTABS 128 vim_free(beval->vts); 129 beval->vts = tabstop_copy(wp->w_buffer->b_p_vts_array); 130 #endif 131 beval->ts = wp->w_buffer->b_p_ts; 132 return OK; 133 } 134 } 135 } 136 137 return FAIL; 138 } 139 140 /* 141 * Show a balloon with "mesg" or "list". 142 */ 143 void 144 post_balloon(BalloonEval *beval UNUSED, char_u *mesg, list_T *list UNUSED) 145 { 146 # ifdef FEAT_BEVAL_TERM 147 # ifdef FEAT_GUI 148 if (!gui.in_use) 149 # endif 150 ui_post_balloon(mesg, list); 151 # endif 152 # ifdef FEAT_BEVAL_GUI 153 if (gui.in_use) 154 /* GUI can't handle a list */ 155 gui_mch_post_balloon(beval, mesg); 156 # endif 157 } 158 159 /* 160 * Returns TRUE if the balloon eval has been enabled: 161 * 'ballooneval' for the GUI and 'balloonevalterm' for the terminal. 162 * Also checks if the screen isn't scrolled up. 163 */ 164 int 165 can_use_beval(void) 166 { 167 return (0 168 #ifdef FEAT_BEVAL_GUI 169 || (gui.in_use && p_beval) 170 #endif 171 #ifdef FEAT_BEVAL_TERM 172 || ( 173 # ifdef FEAT_GUI 174 !gui.in_use && 175 # endif 176 p_bevalterm) 177 #endif 178 ) && msg_scrolled == 0; 179 } 180 181 /* 182 * Common code, invoked when the mouse is resting for a moment. 183 */ 184 void 185 general_beval_cb(BalloonEval *beval, int state UNUSED) 186 { 187 #ifdef FEAT_EVAL 188 win_T *wp; 189 int col; 190 int use_sandbox; 191 linenr_T lnum; 192 char_u *text; 193 static char_u *result = NULL; 194 long winnr = 0; 195 char_u *bexpr; 196 buf_T *save_curbuf; 197 size_t len; 198 win_T *cw; 199 #endif 200 static int recursive = FALSE; 201 202 /* Don't do anything when 'ballooneval' is off, messages scrolled the 203 * windows up or we have no beval area. */ 204 if (!can_use_beval() || beval == NULL) 205 return; 206 207 /* Don't do this recursively. Happens when the expression evaluation 208 * takes a long time and invokes something that checks for CTRL-C typed. */ 209 if (recursive) 210 return; 211 recursive = TRUE; 212 213 #ifdef FEAT_EVAL 214 if (get_beval_info(beval, TRUE, &wp, &lnum, &text, &col) == OK) 215 { 216 bexpr = (*wp->w_buffer->b_p_bexpr == NUL) ? p_bexpr 217 : wp->w_buffer->b_p_bexpr; 218 if (*bexpr != NUL) 219 { 220 /* Convert window pointer to number. */ 221 for (cw = firstwin; cw != wp; cw = cw->w_next) 222 ++winnr; 223 224 set_vim_var_nr(VV_BEVAL_BUFNR, (long)wp->w_buffer->b_fnum); 225 set_vim_var_nr(VV_BEVAL_WINNR, winnr); 226 set_vim_var_nr(VV_BEVAL_WINID, wp->w_id); 227 set_vim_var_nr(VV_BEVAL_LNUM, (long)lnum); 228 set_vim_var_nr(VV_BEVAL_COL, (long)(col + 1)); 229 set_vim_var_string(VV_BEVAL_TEXT, text, -1); 230 vim_free(text); 231 232 /* 233 * Temporarily change the curbuf, so that we can determine whether 234 * the buffer-local balloonexpr option was set insecurely. 235 */ 236 save_curbuf = curbuf; 237 curbuf = wp->w_buffer; 238 use_sandbox = was_set_insecurely((char_u *)"balloonexpr", 239 *curbuf->b_p_bexpr == NUL ? 0 : OPT_LOCAL); 240 curbuf = save_curbuf; 241 if (use_sandbox) 242 ++sandbox; 243 ++textlock; 244 245 vim_free(result); 246 result = eval_to_string(bexpr, NULL, TRUE); 247 248 /* Remove one trailing newline, it is added when the result was a 249 * list and it's hardly ever useful. If the user really wants a 250 * trailing newline he can add two and one remains. */ 251 if (result != NULL) 252 { 253 len = STRLEN(result); 254 if (len > 0 && result[len - 1] == NL) 255 result[len - 1] = NUL; 256 } 257 258 if (use_sandbox) 259 --sandbox; 260 --textlock; 261 262 set_vim_var_string(VV_BEVAL_TEXT, NULL, -1); 263 if (result != NULL && result[0] != NUL) 264 { 265 post_balloon(beval, result, NULL); 266 recursive = FALSE; 267 return; 268 } 269 } 270 } 271 #endif 272 #ifdef FEAT_NETBEANS_INTG 273 if (bevalServers & BEVAL_NETBEANS) 274 netbeans_beval_cb(beval, state); 275 #endif 276 277 recursive = FALSE; 278 } 279 280 #endif 281 282