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