blob: 193964667abc62bc1574786e4caffda61eb1d0dc [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 Moolenaar99a764b2019-07-17 20:01:48 +020013#if defined(FEAT_BEVAL) || defined(FEAT_TEXT_PROP) || 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);
Bram Moolenaar1ad022a2017-12-03 18:20:32 +010042 if (wp != NULL && row >= 0 && row < wp->w_height && col < wp->w_width)
Bram Moolenaarc3719bd2017-11-18 22:13:31 +010043 {
Bram Moolenaarb3d17a22019-07-07 18:28:14 +020044 // Found a window and the cursor is in the text. Now find the line
45 // number.
Bram Moolenaarc3719bd2017-11-18 22:13:31 +010046 if (!mouse_comp_pos(wp, &row, &col, &lnum))
47 {
Bram Moolenaarb3d17a22019-07-07 18:28:14 +020048 // Not past end of the file.
Bram Moolenaarc3719bd2017-11-18 22:13:31 +010049 lbuf = ml_get_buf(wp->w_buffer, lnum, FALSE);
50 if (col <= win_linetabsize(wp, lbuf, (colnr_T)MAXCOL))
51 {
Bram Moolenaarb3d17a22019-07-07 18:28:14 +020052 // Not past end of line.
Bram Moolenaarc3719bd2017-11-18 22:13:31 +010053 if (getword)
54 {
Bram Moolenaarb3d17a22019-07-07 18:28:14 +020055 // For Netbeans we get the relevant part of the line
56 // instead of the whole line.
Bram Moolenaarc3719bd2017-11-18 22:13:31 +010057 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
76 if (VIsual_active
77 && wp->w_buffer == curwin->w_buffer
78 && (lnum == spos->lnum
79 ? col >= (int)spos->col
80 : lnum > spos->lnum)
81 && (lnum == epos->lnum
82 ? col <= (int)epos->col
83 : lnum < epos->lnum))
84 {
Bram Moolenaarb3d17a22019-07-07 18:28:14 +020085 // Visual mode and pointing to the line with the
86 // Visual selection: return selected text, with a
87 // maximum of one line.
Bram Moolenaarc3719bd2017-11-18 22:13:31 +010088 if (spos->lnum != epos->lnum || spos->col == epos->col)
89 return FAIL;
90
91 lbuf = ml_get_buf(curwin->w_buffer, VIsual.lnum, FALSE);
92 len = epos->col - spos->col;
93 if (*p_sel != 'e')
94 len += MB_PTR2LEN(lbuf + epos->col);
95 lbuf = vim_strnsave(lbuf + spos->col, len);
96 lnum = spos->lnum;
97 col = spos->col;
98 }
99 else
100 {
Bram Moolenaarb3d17a22019-07-07 18:28:14 +0200101 // Find the word under the cursor.
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100102 ++emsg_off;
Bram Moolenaar7ba343e2019-07-09 23:22:15 +0200103 len = find_ident_at_pos(wp, lnum, (colnr_T)col,
104 &lbuf, &scol, flags);
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100105 --emsg_off;
106 if (len == 0)
107 return FAIL;
108 lbuf = vim_strnsave(lbuf, len);
109 }
110 }
111
Bram Moolenaarb3d17a22019-07-07 18:28:14 +0200112 if (winp != NULL)
113 *winp = wp;
114 if (lnump != NULL)
115 *lnump = lnum;
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100116 *textp = lbuf;
Bram Moolenaar7ba343e2019-07-09 23:22:15 +0200117 if (colp != NULL)
118 *colp = col;
119 if (startcolp != NULL)
120 *startcolp = scol;
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100121 return OK;
122 }
123 }
124 }
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100125 return FAIL;
126}
Bram Moolenaar3f3e9542019-07-07 20:30:48 +0200127#endif
128
129#if defined(FEAT_BEVAL) || defined(PROTO)
130
131/*
132 * Get the text and position to be evaluated for "beval".
133 * If "getword" is TRUE the returned text is not the whole line but the
134 * relevant word in allocated memory.
135 * Returns OK or FAIL.
136 */
137 int
138get_beval_info(
Bram Moolenaaree9e6042019-07-08 20:08:44 +0200139 BalloonEval *beval,
140 int getword,
141 win_T **winp,
142 linenr_T *lnump,
143 char_u **textp,
144 int *colp)
Bram Moolenaar3f3e9542019-07-07 20:30:48 +0200145{
Bram Moolenaaree9e6042019-07-08 20:08:44 +0200146 int row = mouse_row;
147 int col = mouse_col;
Bram Moolenaar3f3e9542019-07-07 20:30:48 +0200148
Bram Moolenaar3f3e9542019-07-07 20:30:48 +0200149# ifdef FEAT_GUI
150 if (gui.in_use)
151 {
152 row = Y_2_ROW(beval->y);
153 col = X_2_COL(beval->x);
154 }
155#endif
156 if (find_word_under_cursor(row, col, getword,
157 FIND_IDENT + FIND_STRING + FIND_EVAL,
Bram Moolenaar7ba343e2019-07-09 23:22:15 +0200158 winp, lnump, textp, colp, NULL) == OK)
Bram Moolenaar3f3e9542019-07-07 20:30:48 +0200159 {
160#ifdef FEAT_VARTABS
161 vim_free(beval->vts);
162 beval->vts = tabstop_copy((*winp)->w_buffer->b_p_vts_array);
163 if ((*winp)->w_buffer->b_p_vts_array != NULL && beval->vts == NULL)
164 {
165 if (getword)
166 vim_free(*textp);
167 return FAIL;
168 }
169#endif
170 beval->ts = (*winp)->w_buffer->b_p_ts;
171 return OK;
172 }
173
174 return FAIL;
175}
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100176
177/*
Bram Moolenaar246fe032017-11-19 19:56:27 +0100178 * Show a balloon with "mesg" or "list".
Bram Moolenaar451d4b52019-06-12 20:22:27 +0200179 * Hide the balloon when both are NULL.
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100180 */
181 void
Bram Moolenaar792f0e32018-02-27 17:27:13 +0100182post_balloon(BalloonEval *beval UNUSED, char_u *mesg, list_T *list UNUSED)
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100183{
184# ifdef FEAT_BEVAL_TERM
185# ifdef FEAT_GUI
186 if (!gui.in_use)
187# endif
Bram Moolenaar246fe032017-11-19 19:56:27 +0100188 ui_post_balloon(mesg, list);
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100189# endif
190# ifdef FEAT_BEVAL_GUI
191 if (gui.in_use)
Bram Moolenaar451d4b52019-06-12 20:22:27 +0200192 // GUI can't handle a list
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100193 gui_mch_post_balloon(beval, mesg);
194# endif
195}
196
197/*
198 * Returns TRUE if the balloon eval has been enabled:
199 * 'ballooneval' for the GUI and 'balloonevalterm' for the terminal.
200 * Also checks if the screen isn't scrolled up.
201 */
202 int
203can_use_beval(void)
204{
205 return (0
206#ifdef FEAT_BEVAL_GUI
207 || (gui.in_use && p_beval)
208#endif
209#ifdef FEAT_BEVAL_TERM
210 || (
211# ifdef FEAT_GUI
212 !gui.in_use &&
213# endif
214 p_bevalterm)
215#endif
216 ) && msg_scrolled == 0;
217}
218
219/*
220 * Common code, invoked when the mouse is resting for a moment.
221 */
222 void
223general_beval_cb(BalloonEval *beval, int state UNUSED)
224{
225#ifdef FEAT_EVAL
226 win_T *wp;
227 int col;
228 int use_sandbox;
229 linenr_T lnum;
230 char_u *text;
231 static char_u *result = NULL;
232 long winnr = 0;
233 char_u *bexpr;
234 buf_T *save_curbuf;
235 size_t len;
236 win_T *cw;
237#endif
238 static int recursive = FALSE;
239
240 /* Don't do anything when 'ballooneval' is off, messages scrolled the
241 * windows up or we have no beval area. */
242 if (!can_use_beval() || beval == NULL)
243 return;
244
245 /* Don't do this recursively. Happens when the expression evaluation
246 * takes a long time and invokes something that checks for CTRL-C typed. */
247 if (recursive)
248 return;
249 recursive = TRUE;
250
251#ifdef FEAT_EVAL
252 if (get_beval_info(beval, TRUE, &wp, &lnum, &text, &col) == OK)
253 {
254 bexpr = (*wp->w_buffer->b_p_bexpr == NUL) ? p_bexpr
255 : wp->w_buffer->b_p_bexpr;
256 if (*bexpr != NUL)
257 {
258 /* Convert window pointer to number. */
259 for (cw = firstwin; cw != wp; cw = cw->w_next)
260 ++winnr;
261
262 set_vim_var_nr(VV_BEVAL_BUFNR, (long)wp->w_buffer->b_fnum);
263 set_vim_var_nr(VV_BEVAL_WINNR, winnr);
264 set_vim_var_nr(VV_BEVAL_WINID, wp->w_id);
265 set_vim_var_nr(VV_BEVAL_LNUM, (long)lnum);
266 set_vim_var_nr(VV_BEVAL_COL, (long)(col + 1));
267 set_vim_var_string(VV_BEVAL_TEXT, text, -1);
268 vim_free(text);
269
270 /*
271 * Temporarily change the curbuf, so that we can determine whether
272 * the buffer-local balloonexpr option was set insecurely.
273 */
274 save_curbuf = curbuf;
275 curbuf = wp->w_buffer;
276 use_sandbox = was_set_insecurely((char_u *)"balloonexpr",
277 *curbuf->b_p_bexpr == NUL ? 0 : OPT_LOCAL);
278 curbuf = save_curbuf;
279 if (use_sandbox)
280 ++sandbox;
281 ++textlock;
282
283 vim_free(result);
284 result = eval_to_string(bexpr, NULL, TRUE);
285
286 /* Remove one trailing newline, it is added when the result was a
287 * list and it's hardly ever useful. If the user really wants a
288 * trailing newline he can add two and one remains. */
289 if (result != NULL)
290 {
291 len = STRLEN(result);
292 if (len > 0 && result[len - 1] == NL)
293 result[len - 1] = NUL;
294 }
295
296 if (use_sandbox)
297 --sandbox;
298 --textlock;
299
300 set_vim_var_string(VV_BEVAL_TEXT, NULL, -1);
301 if (result != NULL && result[0] != NUL)
Bram Moolenaar246fe032017-11-19 19:56:27 +0100302 post_balloon(beval, result, NULL);
Bram Moolenaar8a7383b2019-07-08 22:23:33 +0200303
Bram Moolenaar8a7383b2019-07-08 22:23:33 +0200304 // The 'balloonexpr' evaluation may show something on the screen
305 // that requires a screen update.
Bram Moolenaar7ba343e2019-07-09 23:22:15 +0200306 if (must_redraw)
Bram Moolenaar8a7383b2019-07-08 22:23:33 +0200307 redraw_after_callback(FALSE);
Bram Moolenaar8a7383b2019-07-08 22:23:33 +0200308
309 recursive = FALSE;
310 return;
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100311 }
312 }
313#endif
314#ifdef FEAT_NETBEANS_INTG
315 if (bevalServers & BEVAL_NETBEANS)
316 netbeans_beval_cb(beval, state);
317#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100318
319 recursive = FALSE;
320}
321
322#endif
323