blob: ef307c5246fb2cb1c574a1261e664f552bdab1cf [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 Moolenaar3f3e9542019-07-07 20:30:48 +020013#if defined(FEAT_BEVAL) || defined(FEAT_TEXT_PROP) || defined(PROT)
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,
30 int *colp)
31{
32 int row = mouserow;
33 int col = mousecol;
34 win_T *wp;
35 char_u *lbuf;
36 linenr_T lnum;
37
38 *textp = NULL;
Bram Moolenaar451d4b52019-06-12 20:22:27 +020039 wp = mouse_find_win(&row, &col, FAIL_POPUP);
Bram Moolenaar1ad022a2017-12-03 18:20:32 +010040 if (wp != NULL && row >= 0 && row < wp->w_height && col < wp->w_width)
Bram Moolenaarc3719bd2017-11-18 22:13:31 +010041 {
Bram Moolenaarb3d17a22019-07-07 18:28:14 +020042 // Found a window and the cursor is in the text. Now find the line
43 // number.
Bram Moolenaarc3719bd2017-11-18 22:13:31 +010044 if (!mouse_comp_pos(wp, &row, &col, &lnum))
45 {
Bram Moolenaarb3d17a22019-07-07 18:28:14 +020046 // Not past end of the file.
Bram Moolenaarc3719bd2017-11-18 22:13:31 +010047 lbuf = ml_get_buf(wp->w_buffer, lnum, FALSE);
48 if (col <= win_linetabsize(wp, lbuf, (colnr_T)MAXCOL))
49 {
Bram Moolenaarb3d17a22019-07-07 18:28:14 +020050 // Not past end of line.
Bram Moolenaarc3719bd2017-11-18 22:13:31 +010051 if (getword)
52 {
Bram Moolenaarb3d17a22019-07-07 18:28:14 +020053 // For Netbeans we get the relevant part of the line
54 // instead of the whole line.
Bram Moolenaarc3719bd2017-11-18 22:13:31 +010055 int len;
56 pos_T *spos = NULL, *epos = NULL;
57
58 if (VIsual_active)
59 {
60 if (LT_POS(VIsual, curwin->w_cursor))
61 {
62 spos = &VIsual;
63 epos = &curwin->w_cursor;
64 }
65 else
66 {
67 spos = &curwin->w_cursor;
68 epos = &VIsual;
69 }
70 }
71
72 col = vcol2col(wp, lnum, col);
73
74 if (VIsual_active
75 && wp->w_buffer == curwin->w_buffer
76 && (lnum == spos->lnum
77 ? col >= (int)spos->col
78 : lnum > spos->lnum)
79 && (lnum == epos->lnum
80 ? col <= (int)epos->col
81 : lnum < epos->lnum))
82 {
Bram Moolenaarb3d17a22019-07-07 18:28:14 +020083 // Visual mode and pointing to the line with the
84 // Visual selection: return selected text, with a
85 // maximum of one line.
Bram Moolenaarc3719bd2017-11-18 22:13:31 +010086 if (spos->lnum != epos->lnum || spos->col == epos->col)
87 return FAIL;
88
89 lbuf = ml_get_buf(curwin->w_buffer, VIsual.lnum, FALSE);
90 len = epos->col - spos->col;
91 if (*p_sel != 'e')
92 len += MB_PTR2LEN(lbuf + epos->col);
93 lbuf = vim_strnsave(lbuf + spos->col, len);
94 lnum = spos->lnum;
95 col = spos->col;
96 }
97 else
98 {
Bram Moolenaarb3d17a22019-07-07 18:28:14 +020099 // Find the word under the cursor.
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100100 ++emsg_off;
101 len = find_ident_at_pos(wp, lnum, (colnr_T)col, &lbuf,
Bram Moolenaarb3d17a22019-07-07 18:28:14 +0200102 flags);
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100103 --emsg_off;
104 if (len == 0)
105 return FAIL;
106 lbuf = vim_strnsave(lbuf, len);
107 }
108 }
109
Bram Moolenaarb3d17a22019-07-07 18:28:14 +0200110 if (winp != NULL)
111 *winp = wp;
112 if (lnump != NULL)
113 *lnump = lnum;
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100114 *textp = lbuf;
115 *colp = col;
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100116 return OK;
117 }
118 }
119 }
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100120 return FAIL;
121}
Bram Moolenaar3f3e9542019-07-07 20:30:48 +0200122#endif
123
124#if defined(FEAT_BEVAL) || defined(PROTO)
125
126/*
127 * Get the text and position to be evaluated for "beval".
128 * If "getword" is TRUE the returned text is not the whole line but the
129 * relevant word in allocated memory.
130 * Returns OK or FAIL.
131 */
132 int
133get_beval_info(
Bram Moolenaaree9e6042019-07-08 20:08:44 +0200134 BalloonEval *beval,
135 int getword,
136 win_T **winp,
137 linenr_T *lnump,
138 char_u **textp,
139 int *colp)
Bram Moolenaar3f3e9542019-07-07 20:30:48 +0200140{
Bram Moolenaaree9e6042019-07-08 20:08:44 +0200141 int row = mouse_row;
142 int col = mouse_col;
Bram Moolenaar3f3e9542019-07-07 20:30:48 +0200143
Bram Moolenaar3f3e9542019-07-07 20:30:48 +0200144# ifdef FEAT_GUI
145 if (gui.in_use)
146 {
147 row = Y_2_ROW(beval->y);
148 col = X_2_COL(beval->x);
149 }
150#endif
151 if (find_word_under_cursor(row, col, getword,
152 FIND_IDENT + FIND_STRING + FIND_EVAL,
153 winp, lnump, textp, colp) == OK)
154 {
155#ifdef FEAT_VARTABS
156 vim_free(beval->vts);
157 beval->vts = tabstop_copy((*winp)->w_buffer->b_p_vts_array);
158 if ((*winp)->w_buffer->b_p_vts_array != NULL && beval->vts == NULL)
159 {
160 if (getword)
161 vim_free(*textp);
162 return FAIL;
163 }
164#endif
165 beval->ts = (*winp)->w_buffer->b_p_ts;
166 return OK;
167 }
168
169 return FAIL;
170}
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100171
172/*
Bram Moolenaar246fe032017-11-19 19:56:27 +0100173 * Show a balloon with "mesg" or "list".
Bram Moolenaar451d4b52019-06-12 20:22:27 +0200174 * Hide the balloon when both are NULL.
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100175 */
176 void
Bram Moolenaar792f0e32018-02-27 17:27:13 +0100177post_balloon(BalloonEval *beval UNUSED, char_u *mesg, list_T *list UNUSED)
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100178{
179# ifdef FEAT_BEVAL_TERM
180# ifdef FEAT_GUI
181 if (!gui.in_use)
182# endif
Bram Moolenaar246fe032017-11-19 19:56:27 +0100183 ui_post_balloon(mesg, list);
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100184# endif
185# ifdef FEAT_BEVAL_GUI
186 if (gui.in_use)
Bram Moolenaar451d4b52019-06-12 20:22:27 +0200187 // GUI can't handle a list
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100188 gui_mch_post_balloon(beval, mesg);
189# endif
190}
191
192/*
193 * Returns TRUE if the balloon eval has been enabled:
194 * 'ballooneval' for the GUI and 'balloonevalterm' for the terminal.
195 * Also checks if the screen isn't scrolled up.
196 */
197 int
198can_use_beval(void)
199{
200 return (0
201#ifdef FEAT_BEVAL_GUI
202 || (gui.in_use && p_beval)
203#endif
204#ifdef FEAT_BEVAL_TERM
205 || (
206# ifdef FEAT_GUI
207 !gui.in_use &&
208# endif
209 p_bevalterm)
210#endif
211 ) && msg_scrolled == 0;
212}
213
214/*
215 * Common code, invoked when the mouse is resting for a moment.
216 */
217 void
218general_beval_cb(BalloonEval *beval, int state UNUSED)
219{
220#ifdef FEAT_EVAL
221 win_T *wp;
222 int col;
223 int use_sandbox;
224 linenr_T lnum;
225 char_u *text;
226 static char_u *result = NULL;
227 long winnr = 0;
228 char_u *bexpr;
229 buf_T *save_curbuf;
230 size_t len;
231 win_T *cw;
232#endif
233 static int recursive = FALSE;
234
235 /* Don't do anything when 'ballooneval' is off, messages scrolled the
236 * windows up or we have no beval area. */
237 if (!can_use_beval() || beval == NULL)
238 return;
239
240 /* Don't do this recursively. Happens when the expression evaluation
241 * takes a long time and invokes something that checks for CTRL-C typed. */
242 if (recursive)
243 return;
244 recursive = TRUE;
245
246#ifdef FEAT_EVAL
247 if (get_beval_info(beval, TRUE, &wp, &lnum, &text, &col) == OK)
248 {
249 bexpr = (*wp->w_buffer->b_p_bexpr == NUL) ? p_bexpr
250 : wp->w_buffer->b_p_bexpr;
251 if (*bexpr != NUL)
252 {
253 /* Convert window pointer to number. */
254 for (cw = firstwin; cw != wp; cw = cw->w_next)
255 ++winnr;
256
257 set_vim_var_nr(VV_BEVAL_BUFNR, (long)wp->w_buffer->b_fnum);
258 set_vim_var_nr(VV_BEVAL_WINNR, winnr);
259 set_vim_var_nr(VV_BEVAL_WINID, wp->w_id);
260 set_vim_var_nr(VV_BEVAL_LNUM, (long)lnum);
261 set_vim_var_nr(VV_BEVAL_COL, (long)(col + 1));
262 set_vim_var_string(VV_BEVAL_TEXT, text, -1);
263 vim_free(text);
264
265 /*
266 * Temporarily change the curbuf, so that we can determine whether
267 * the buffer-local balloonexpr option was set insecurely.
268 */
269 save_curbuf = curbuf;
270 curbuf = wp->w_buffer;
271 use_sandbox = was_set_insecurely((char_u *)"balloonexpr",
272 *curbuf->b_p_bexpr == NUL ? 0 : OPT_LOCAL);
273 curbuf = save_curbuf;
274 if (use_sandbox)
275 ++sandbox;
276 ++textlock;
277
278 vim_free(result);
279 result = eval_to_string(bexpr, NULL, TRUE);
280
281 /* Remove one trailing newline, it is added when the result was a
282 * list and it's hardly ever useful. If the user really wants a
283 * trailing newline he can add two and one remains. */
284 if (result != NULL)
285 {
286 len = STRLEN(result);
287 if (len > 0 && result[len - 1] == NL)
288 result[len - 1] = NUL;
289 }
290
291 if (use_sandbox)
292 --sandbox;
293 --textlock;
294
295 set_vim_var_string(VV_BEVAL_TEXT, NULL, -1);
296 if (result != NULL && result[0] != NUL)
Bram Moolenaar246fe032017-11-19 19:56:27 +0100297 post_balloon(beval, result, NULL);
Bram Moolenaar8a7383b2019-07-08 22:23:33 +0200298
299# ifdef FEAT_GUI
300 // The 'balloonexpr' evaluation may show something on the screen
301 // that requires a screen update.
302 if (gui.in_use && must_redraw)
303 redraw_after_callback(FALSE);
304# endif
305
306 recursive = FALSE;
307 return;
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100308 }
309 }
310#endif
311#ifdef FEAT_NETBEANS_INTG
312 if (bevalServers & BEVAL_NETBEANS)
313 netbeans_beval_cb(beval, state);
314#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100315
316 recursive = FALSE;
317}
318
319#endif
320