blob: 6b10a654d8557c822a17f0e592bc9cae28442795 [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);
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')
Bram Moolenaar1614a142019-10-06 22:00:13 +020095 len += mb_ptr2len(lbuf + epos->col);
Bram Moolenaarc3719bd2017-11-18 22:13:31 +010096 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 }
Bram Moolenaar8d4ed112020-04-04 14:50:32 +0200113 else
114 scol = col;
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100115
Bram Moolenaarb3d17a22019-07-07 18:28:14 +0200116 if (winp != NULL)
117 *winp = wp;
118 if (lnump != NULL)
119 *lnump = lnum;
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100120 *textp = lbuf;
Bram Moolenaar7ba343e2019-07-09 23:22:15 +0200121 if (colp != NULL)
122 *colp = col;
123 if (startcolp != NULL)
124 *startcolp = scol;
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100125 return OK;
126 }
127 }
128 }
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100129 return FAIL;
130}
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
Bram Moolenaar3f3e9542019-07-07 20:30:48 +0200153# 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,
Bram Moolenaar7ba343e2019-07-09 23:22:15 +0200162 winp, lnump, textp, colp, NULL) == OK)
Bram Moolenaar3f3e9542019-07-07 20:30:48 +0200163 {
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}
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
223/*
224 * Common code, invoked when the mouse is resting for a moment.
225 */
226 void
227general_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
Bram Moolenaarc667da52019-11-30 20:52:27 +0100244 // Don't do anything when 'ballooneval' is off, messages scrolled the
245 // windows up or we have no beval area.
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100246 if (!can_use_beval() || beval == NULL)
247 return;
248
Bram Moolenaarc667da52019-11-30 20:52:27 +0100249 // Don't do this recursively. Happens when the expression evaluation
250 // takes a long time and invokes something that checks for CTRL-C typed.
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100251 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 {
Bram Moolenaarc667da52019-11-30 20:52:27 +0100262 // Convert window pointer to number.
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100263 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 ++textlock;
286
287 vim_free(result);
288 result = eval_to_string(bexpr, NULL, TRUE);
289
Bram Moolenaarc667da52019-11-30 20:52:27 +0100290 // 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.
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100293 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 --textlock;
303
304 set_vim_var_string(VV_BEVAL_TEXT, NULL, -1);
305 if (result != NULL && result[0] != NUL)
Bram Moolenaar246fe032017-11-19 19:56:27 +0100306 post_balloon(beval, result, NULL);
Bram Moolenaar8a7383b2019-07-08 22:23:33 +0200307
Bram Moolenaar8a7383b2019-07-08 22:23:33 +0200308 // The 'balloonexpr' evaluation may show something on the screen
309 // that requires a screen update.
Bram Moolenaar7ba343e2019-07-09 23:22:15 +0200310 if (must_redraw)
Bram Moolenaar8a7383b2019-07-08 22:23:33 +0200311 redraw_after_callback(FALSE);
Bram Moolenaar8a7383b2019-07-08 22:23:33 +0200312
313 recursive = FALSE;
314 return;
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100315 }
316 }
317#endif
318#ifdef FEAT_NETBEANS_INTG
319 if (bevalServers & BEVAL_NETBEANS)
320 netbeans_beval_cb(beval, state);
321#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100322
323 recursive = FALSE;
324}
325
326#endif