blob: 69e667d63971e78cd4742a99ed527c0eac18f9bd [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 Moolenaar9d5ffce2019-07-26 21:01:29 +020046 if (!mouse_comp_pos(wp, &row, &col, &lnum, NULL))
Bram Moolenaarc3719bd2017-11-18 22:13:31 +010047 {
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);
Bram Moolenaar3fb4f472019-07-17 21:32:14 +020075 scol = col;
Bram Moolenaarc3719bd2017-11-18 22:13:31 +010076
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 {
Bram Moolenaarb3d17a22019-07-07 18:28:14 +020086 // Visual mode and pointing to the line with the
87 // Visual selection: return selected text, with a
88 // maximum of one line.
Bram Moolenaarc3719bd2017-11-18 22:13:31 +010089 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;
Bram Moolenaar3fb4f472019-07-17 21:32:14 +020099 scol = col;
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100100 }
101 else
102 {
Bram Moolenaarb3d17a22019-07-07 18:28:14 +0200103 // Find the word under the cursor.
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100104 ++emsg_off;
Bram Moolenaar7ba343e2019-07-09 23:22:15 +0200105 len = find_ident_at_pos(wp, lnum, (colnr_T)col,
106 &lbuf, &scol, flags);
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100107 --emsg_off;
108 if (len == 0)
109 return FAIL;
110 lbuf = vim_strnsave(lbuf, len);
111 }
112 }
113
Bram Moolenaarb3d17a22019-07-07 18:28:14 +0200114 if (winp != NULL)
115 *winp = wp;
116 if (lnump != NULL)
117 *lnump = lnum;
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100118 *textp = lbuf;
Bram Moolenaar7ba343e2019-07-09 23:22:15 +0200119 if (colp != NULL)
120 *colp = col;
121 if (startcolp != NULL)
122 *startcolp = scol;
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100123 return OK;
124 }
125 }
126 }
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100127 return FAIL;
128}
Bram Moolenaar3f3e9542019-07-07 20:30:48 +0200129#endif
130
131#if defined(FEAT_BEVAL) || defined(PROTO)
132
133/*
134 * Get the text and position to be evaluated for "beval".
135 * If "getword" is TRUE the returned text is not the whole line but the
136 * relevant word in allocated memory.
137 * Returns OK or FAIL.
138 */
139 int
140get_beval_info(
Bram Moolenaaree9e6042019-07-08 20:08:44 +0200141 BalloonEval *beval,
142 int getword,
143 win_T **winp,
144 linenr_T *lnump,
145 char_u **textp,
146 int *colp)
Bram Moolenaar3f3e9542019-07-07 20:30:48 +0200147{
Bram Moolenaaree9e6042019-07-08 20:08:44 +0200148 int row = mouse_row;
149 int col = mouse_col;
Bram Moolenaar3f3e9542019-07-07 20:30:48 +0200150
Bram Moolenaar3f3e9542019-07-07 20:30:48 +0200151# ifdef FEAT_GUI
152 if (gui.in_use)
153 {
154 row = Y_2_ROW(beval->y);
155 col = X_2_COL(beval->x);
156 }
157#endif
158 if (find_word_under_cursor(row, col, getword,
159 FIND_IDENT + FIND_STRING + FIND_EVAL,
Bram Moolenaar7ba343e2019-07-09 23:22:15 +0200160 winp, lnump, textp, colp, NULL) == OK)
Bram Moolenaar3f3e9542019-07-07 20:30:48 +0200161 {
162#ifdef FEAT_VARTABS
163 vim_free(beval->vts);
164 beval->vts = tabstop_copy((*winp)->w_buffer->b_p_vts_array);
165 if ((*winp)->w_buffer->b_p_vts_array != NULL && beval->vts == NULL)
166 {
167 if (getword)
168 vim_free(*textp);
169 return FAIL;
170 }
171#endif
172 beval->ts = (*winp)->w_buffer->b_p_ts;
173 return OK;
174 }
175
176 return FAIL;
177}
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100178
179/*
Bram Moolenaar246fe032017-11-19 19:56:27 +0100180 * Show a balloon with "mesg" or "list".
Bram Moolenaar451d4b52019-06-12 20:22:27 +0200181 * Hide the balloon when both are NULL.
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100182 */
183 void
Bram Moolenaar792f0e32018-02-27 17:27:13 +0100184post_balloon(BalloonEval *beval UNUSED, char_u *mesg, list_T *list UNUSED)
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100185{
186# ifdef FEAT_BEVAL_TERM
187# ifdef FEAT_GUI
188 if (!gui.in_use)
189# endif
Bram Moolenaar246fe032017-11-19 19:56:27 +0100190 ui_post_balloon(mesg, list);
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100191# endif
192# ifdef FEAT_BEVAL_GUI
193 if (gui.in_use)
Bram Moolenaar451d4b52019-06-12 20:22:27 +0200194 // GUI can't handle a list
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100195 gui_mch_post_balloon(beval, mesg);
196# endif
197}
198
199/*
200 * Returns TRUE if the balloon eval has been enabled:
201 * 'ballooneval' for the GUI and 'balloonevalterm' for the terminal.
202 * Also checks if the screen isn't scrolled up.
203 */
204 int
205can_use_beval(void)
206{
207 return (0
208#ifdef FEAT_BEVAL_GUI
209 || (gui.in_use && p_beval)
210#endif
211#ifdef FEAT_BEVAL_TERM
212 || (
213# ifdef FEAT_GUI
214 !gui.in_use &&
215# endif
216 p_bevalterm)
217#endif
218 ) && msg_scrolled == 0;
219}
220
221/*
222 * Common code, invoked when the mouse is resting for a moment.
223 */
224 void
225general_beval_cb(BalloonEval *beval, int state UNUSED)
226{
227#ifdef FEAT_EVAL
228 win_T *wp;
229 int col;
230 int use_sandbox;
231 linenr_T lnum;
232 char_u *text;
233 static char_u *result = NULL;
234 long winnr = 0;
235 char_u *bexpr;
236 buf_T *save_curbuf;
237 size_t len;
238 win_T *cw;
239#endif
240 static int recursive = FALSE;
241
242 /* Don't do anything when 'ballooneval' is off, messages scrolled the
243 * windows up or we have no beval area. */
244 if (!can_use_beval() || beval == NULL)
245 return;
246
247 /* Don't do this recursively. Happens when the expression evaluation
248 * takes a long time and invokes something that checks for CTRL-C typed. */
249 if (recursive)
250 return;
251 recursive = TRUE;
252
253#ifdef FEAT_EVAL
254 if (get_beval_info(beval, TRUE, &wp, &lnum, &text, &col) == OK)
255 {
256 bexpr = (*wp->w_buffer->b_p_bexpr == NUL) ? p_bexpr
257 : wp->w_buffer->b_p_bexpr;
258 if (*bexpr != NUL)
259 {
260 /* Convert window pointer to number. */
261 for (cw = firstwin; cw != wp; cw = cw->w_next)
262 ++winnr;
263
264 set_vim_var_nr(VV_BEVAL_BUFNR, (long)wp->w_buffer->b_fnum);
265 set_vim_var_nr(VV_BEVAL_WINNR, winnr);
266 set_vim_var_nr(VV_BEVAL_WINID, wp->w_id);
267 set_vim_var_nr(VV_BEVAL_LNUM, (long)lnum);
268 set_vim_var_nr(VV_BEVAL_COL, (long)(col + 1));
269 set_vim_var_string(VV_BEVAL_TEXT, text, -1);
270 vim_free(text);
271
272 /*
273 * Temporarily change the curbuf, so that we can determine whether
274 * the buffer-local balloonexpr option was set insecurely.
275 */
276 save_curbuf = curbuf;
277 curbuf = wp->w_buffer;
278 use_sandbox = was_set_insecurely((char_u *)"balloonexpr",
279 *curbuf->b_p_bexpr == NUL ? 0 : OPT_LOCAL);
280 curbuf = save_curbuf;
281 if (use_sandbox)
282 ++sandbox;
283 ++textlock;
284
285 vim_free(result);
286 result = eval_to_string(bexpr, NULL, TRUE);
287
288 /* Remove one trailing newline, it is added when the result was a
289 * list and it's hardly ever useful. If the user really wants a
290 * trailing newline he can add two and one remains. */
291 if (result != NULL)
292 {
293 len = STRLEN(result);
294 if (len > 0 && result[len - 1] == NL)
295 result[len - 1] = NUL;
296 }
297
298 if (use_sandbox)
299 --sandbox;
300 --textlock;
301
302 set_vim_var_string(VV_BEVAL_TEXT, NULL, -1);
303 if (result != NULL && result[0] != NUL)
Bram Moolenaar246fe032017-11-19 19:56:27 +0100304 post_balloon(beval, result, NULL);
Bram Moolenaar8a7383b2019-07-08 22:23:33 +0200305
Bram Moolenaar8a7383b2019-07-08 22:23:33 +0200306 // The 'balloonexpr' evaluation may show something on the screen
307 // that requires a screen update.
Bram Moolenaar7ba343e2019-07-09 23:22:15 +0200308 if (must_redraw)
Bram Moolenaar8a7383b2019-07-08 22:23:33 +0200309 redraw_after_callback(FALSE);
Bram Moolenaar8a7383b2019-07-08 22:23:33 +0200310
311 recursive = FALSE;
312 return;
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100313 }
314 }
315#endif
316#ifdef FEAT_NETBEANS_INTG
317 if (bevalServers & BEVAL_NETBEANS)
318 netbeans_beval_cb(beval, state);
319#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100320
321 recursive = FALSE;
322}
323
324#endif
325