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
find_word_under_cursor(int mouserow,int mousecol,int getword,int flags,win_T ** winp,linenr_T * lnump,char_u ** textp,int * colp,int * startcolp)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
get_beval_info(BalloonEval * beval,int getword,win_T ** winp,linenr_T * lnump,char_u ** textp,int * colp)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
post_balloon(BalloonEval * beval UNUSED,char_u * mesg,list_T * list UNUSED)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
can_use_beval(void)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
general_beval_cb(BalloonEval * beval,int state UNUSED)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