blob: 65dfbc2aadb0f63eb588fa3339ad3e1e03c0d6ec [file] [log] [blame]
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01001/* 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
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +010013#if defined(FEAT_BEVAL) || defined(FEAT_PROP_POPUP) || defined(PROTO)
Bram Moolenaarb3d17a22019-07-07 18:28:14 +020014/*
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
22find_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,
Bram Moolenaar7ba343e2019-07-09 23:22:15 +020030 int *colp, // column where mouse hovers, can be NULL
31 int *startcolp) // column where text starts, can be NULL
Bram Moolenaarb3d17a22019-07-07 18:28:14 +020032{
33 int row = mouserow;
34 int col = mousecol;
Bram Moolenaar7ba343e2019-07-09 23:22:15 +020035 int scol;
Bram Moolenaarb3d17a22019-07-07 18:28:14 +020036 win_T *wp;
37 char_u *lbuf;
38 linenr_T lnum;
39
40 *textp = NULL;
Bram Moolenaar451d4b52019-06-12 20:22:27 +020041 wp = mouse_find_win(&row, &col, FAIL_POPUP);
Yegappan Lakshmanan368aa692022-09-27 11:46:48 +010042 if (wp == NULL || row < 0 || row >= wp->w_height || col >= wp->w_width)
43 return FAIL;
44
45 // Found a window and the cursor is in the text. Now find the line
46 // number.
47 if (mouse_comp_pos(wp, &row, &col, &lnum, NULL))
48 return FAIL; // position is below the last line
49
50 // Not past end of the file.
51 lbuf = ml_get_buf(wp->w_buffer, lnum, FALSE);
52 if (col > win_linetabsize(wp, lnum, lbuf, (colnr_T)MAXCOL))
53 return FAIL; // past end of line
54
55 // Not past end of line.
56 if (getword)
Bram Moolenaarc3719bd2017-11-18 22:13:31 +010057 {
Yegappan Lakshmanan368aa692022-09-27 11:46:48 +010058 // For Netbeans we get the relevant part of the line
59 // instead of the whole line.
60 int len;
61 pos_T *spos = NULL, *epos = NULL;
62
63 if (VIsual_active)
Bram Moolenaarc3719bd2017-11-18 22:13:31 +010064 {
Yegappan Lakshmanan368aa692022-09-27 11:46:48 +010065 if (LT_POS(VIsual, curwin->w_cursor))
Bram Moolenaarc3719bd2017-11-18 22:13:31 +010066 {
Yegappan Lakshmanan368aa692022-09-27 11:46:48 +010067 spos = &VIsual;
68 epos = &curwin->w_cursor;
69 }
70 else
71 {
72 spos = &curwin->w_cursor;
73 epos = &VIsual;
Bram Moolenaarc3719bd2017-11-18 22:13:31 +010074 }
75 }
Yegappan Lakshmanan368aa692022-09-27 11:46:48 +010076
zeertzjqf5a94d52023-10-15 10:03:30 +020077 col = vcol2col(wp, lnum, col, NULL);
Yegappan Lakshmanan368aa692022-09-27 11:46:48 +010078 scol = col;
79
80 if (VIsual_active
81 && wp->w_buffer == curwin->w_buffer
82 && (lnum == spos->lnum
83 ? col >= (int)spos->col
84 : lnum > spos->lnum)
85 && (lnum == epos->lnum
86 ? col <= (int)epos->col
87 : lnum < epos->lnum))
88 {
89 // Visual mode and pointing to the line with the
90 // Visual selection: return selected text, with a
91 // maximum of one line.
92 if (spos->lnum != epos->lnum || spos->col == epos->col)
93 return FAIL;
94
95 lbuf = ml_get_buf(curwin->w_buffer, VIsual.lnum, FALSE);
96 len = epos->col - spos->col;
97 if (*p_sel != 'e')
98 len += mb_ptr2len(lbuf + epos->col);
99 lbuf = vim_strnsave(lbuf + spos->col, len);
100 lnum = spos->lnum;
101 col = spos->col;
102 scol = col;
103 }
104 else
105 {
106 // Find the word under the cursor.
107 ++emsg_off;
108 len = find_ident_at_pos(wp, lnum, (colnr_T)col,
109 &lbuf, &scol, flags);
110 --emsg_off;
111 if (len == 0)
112 return FAIL;
113 lbuf = vim_strnsave(lbuf, len);
114 }
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100115 }
Yegappan Lakshmanan368aa692022-09-27 11:46:48 +0100116 else
117 scol = col;
118
119 if (winp != NULL)
120 *winp = wp;
121 if (lnump != NULL)
122 *lnump = lnum;
123 *textp = lbuf;
124 if (colp != NULL)
125 *colp = col;
126 if (startcolp != NULL)
127 *startcolp = scol;
128
129 return OK;
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100130}
Bram Moolenaar3f3e9542019-07-07 20:30:48 +0200131#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
142get_beval_info(
Bram Moolenaaree9e6042019-07-08 20:08:44 +0200143 BalloonEval *beval,
144 int getword,
145 win_T **winp,
146 linenr_T *lnump,
147 char_u **textp,
148 int *colp)
Bram Moolenaar3f3e9542019-07-07 20:30:48 +0200149{
Bram Moolenaaree9e6042019-07-08 20:08:44 +0200150 int row = mouse_row;
151 int col = mouse_col;
Bram Moolenaar3f3e9542019-07-07 20:30:48 +0200152
h-east8603be32021-12-06 11:24:09 +0000153# ifdef FEAT_BEVAL_GUI
Bram Moolenaar3f3e9542019-07-07 20:30:48 +0200154 if (gui.in_use)
155 {
156 row = Y_2_ROW(beval->y);
157 col = X_2_COL(beval->x);
158 }
h-east8603be32021-12-06 11:24:09 +0000159# endif
Bram Moolenaar3f3e9542019-07-07 20:30:48 +0200160 if (find_word_under_cursor(row, col, getword,
161 FIND_IDENT + FIND_STRING + FIND_EVAL,
Bram Moolenaar7ba343e2019-07-09 23:22:15 +0200162 winp, lnump, textp, colp, NULL) == OK)
Bram Moolenaar3f3e9542019-07-07 20:30:48 +0200163 {
h-east8603be32021-12-06 11:24:09 +0000164# ifdef FEAT_VARTABS
Bram Moolenaar3f3e9542019-07-07 20:30:48 +0200165 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 }
h-east8603be32021-12-06 11:24:09 +0000173# endif
Bram Moolenaar3f3e9542019-07-07 20:30:48 +0200174 beval->ts = (*winp)->w_buffer->b_p_ts;
175 return OK;
176 }
177
178 return FAIL;
179}
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100180
181/*
Bram Moolenaar246fe032017-11-19 19:56:27 +0100182 * Show a balloon with "mesg" or "list".
Bram Moolenaar451d4b52019-06-12 20:22:27 +0200183 * Hide the balloon when both are NULL.
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100184 */
185 void
Bram Moolenaar792f0e32018-02-27 17:27:13 +0100186post_balloon(BalloonEval *beval UNUSED, char_u *mesg, list_T *list UNUSED)
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100187{
188# ifdef FEAT_BEVAL_TERM
189# ifdef FEAT_GUI
190 if (!gui.in_use)
191# endif
Bram Moolenaar246fe032017-11-19 19:56:27 +0100192 ui_post_balloon(mesg, list);
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100193# endif
194# ifdef FEAT_BEVAL_GUI
195 if (gui.in_use)
Bram Moolenaar451d4b52019-06-12 20:22:27 +0200196 // GUI can't handle a list
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100197 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
207can_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
Yegappan Lakshmanan368aa692022-09-27 11:46:48 +0100223# ifdef FEAT_EVAL
224/*
225 * Evaluate the expression 'bexpr' and set the text in the balloon 'beval'.
226 */
227 static void
228bexpr_eval(
229 BalloonEval *beval,
230 char_u *bexpr,
231 win_T *wp,
232 linenr_T lnum,
233 int col,
234 char_u *text)
235{
236 win_T *cw;
237 long winnr = 0;
238 buf_T *save_curbuf;
239 int use_sandbox;
240 static char_u *result = NULL;
241 size_t len;
242
243 sctx_T save_sctx = current_sctx;
244
245 // Convert window pointer to number.
246 for (cw = firstwin; cw != wp; cw = cw->w_next)
247 ++winnr;
248
249 set_vim_var_nr(VV_BEVAL_BUFNR, (long)wp->w_buffer->b_fnum);
250 set_vim_var_nr(VV_BEVAL_WINNR, winnr);
251 set_vim_var_nr(VV_BEVAL_WINID, wp->w_id);
252 set_vim_var_nr(VV_BEVAL_LNUM, (long)lnum);
253 set_vim_var_nr(VV_BEVAL_COL, (long)(col + 1));
254 set_vim_var_string(VV_BEVAL_TEXT, text, -1);
255 vim_free(text);
256
257 /*
258 * Temporarily change the curbuf, so that we can determine whether
259 * the buffer-local balloonexpr option was set insecurely.
260 */
261 save_curbuf = curbuf;
262 curbuf = wp->w_buffer;
263 use_sandbox = was_set_insecurely((char_u *)"balloonexpr",
Bram Moolenaarf39d9e92023-04-22 22:54:40 +0100264 *curbuf->b_p_bexpr == NUL ? 0 : OPT_LOCAL);
Yegappan Lakshmanan368aa692022-09-27 11:46:48 +0100265 curbuf = save_curbuf;
266 if (use_sandbox)
267 ++sandbox;
268 ++textlock;
269
270 if (bexpr == p_bexpr)
271 {
272 sctx_T *sp = get_option_sctx("balloonexpr");
273
274 if (sp != NULL)
275 current_sctx = *sp;
276 }
277 else
278 current_sctx = curbuf->b_p_script_ctx[BV_BEXPR];
279
280 vim_free(result);
Bram Moolenaara4e0b972022-10-01 19:43:52 +0100281 result = eval_to_string(bexpr, TRUE, TRUE);
Yegappan Lakshmanan368aa692022-09-27 11:46:48 +0100282
283 // Remove one trailing newline, it is added when the result was a
284 // list and it's hardly ever useful. If the user really wants a
285 // trailing newline he can add two and one remains.
286 if (result != NULL)
287 {
288 len = STRLEN(result);
289 if (len > 0 && result[len - 1] == NL)
290 result[len - 1] = NUL;
291 }
292
293 if (use_sandbox)
294 --sandbox;
295 --textlock;
296 current_sctx = save_sctx;
297
298 set_vim_var_string(VV_BEVAL_TEXT, NULL, -1);
299 if (result != NULL && result[0] != NUL)
300 post_balloon(beval, result, NULL);
301
302 // The 'balloonexpr' evaluation may show something on the screen
303 // that requires a screen update.
304 if (must_redraw)
305 redraw_after_callback(FALSE, FALSE);
306}
307# endif
308
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100309/*
310 * Common code, invoked when the mouse is resting for a moment.
311 */
312 void
313general_beval_cb(BalloonEval *beval, int state UNUSED)
314{
315#ifdef FEAT_EVAL
316 win_T *wp;
317 int col;
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100318 linenr_T lnum;
319 char_u *text;
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100320 char_u *bexpr;
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100321#endif
322 static int recursive = FALSE;
323
Bram Moolenaarc667da52019-11-30 20:52:27 +0100324 // Don't do anything when 'ballooneval' is off, messages scrolled the
325 // windows up or we have no beval area.
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100326 if (!can_use_beval() || beval == NULL)
327 return;
328
Bram Moolenaarc667da52019-11-30 20:52:27 +0100329 // Don't do this recursively. Happens when the expression evaluation
330 // takes a long time and invokes something that checks for CTRL-C typed.
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100331 if (recursive)
332 return;
333 recursive = TRUE;
334
335#ifdef FEAT_EVAL
336 if (get_beval_info(beval, TRUE, &wp, &lnum, &text, &col) == OK)
337 {
338 bexpr = (*wp->w_buffer->b_p_bexpr == NUL) ? p_bexpr
339 : wp->w_buffer->b_p_bexpr;
340 if (*bexpr != NUL)
341 {
Yegappan Lakshmanan368aa692022-09-27 11:46:48 +0100342 bexpr_eval(beval, bexpr, wp, lnum, col, text);
Bram Moolenaar8a7383b2019-07-08 22:23:33 +0200343 recursive = FALSE;
344 return;
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100345 }
346 }
347#endif
348#ifdef FEAT_NETBEANS_INTG
349 if (bevalServers & BEVAL_NETBEANS)
350 netbeans_beval_cb(beval, state);
351#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100352
353 recursive = FALSE;
354}
355
356#endif