blob: 2cbe7ea1f0539ce337bb7a0aa8cfd73ea0c8d4e7 [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
13#if defined(FEAT_BEVAL) || defined(PROTO)
14
15/*
16 * Get the text and position to be evaluated for "beval".
Bram Moolenaarb3d17a22019-07-07 18:28:14 +020017 * If "getword" is TRUE the returned text is not the whole line but the
Bram Moolenaarc3719bd2017-11-18 22:13:31 +010018 * relevant word in allocated memory.
19 * Returns OK or FAIL.
20 */
21 int
22get_beval_info(
23 BalloonEval *beval,
24 int getword,
25 win_T **winp,
26 linenr_T *lnump,
27 char_u **textp,
28 int *colp)
29{
Bram Moolenaarc3719bd2017-11-18 22:13:31 +010030 int row, col;
Bram Moolenaarc3719bd2017-11-18 22:13:31 +010031
Bram Moolenaarc3719bd2017-11-18 22:13:31 +010032# ifdef FEAT_BEVAL_TERM
33# ifdef FEAT_GUI
34 if (!gui.in_use)
35# endif
36 {
37 row = mouse_row;
38 col = mouse_col;
39 }
40# endif
41# ifdef FEAT_GUI
42 if (gui.in_use)
43 {
44 row = Y_2_ROW(beval->y);
45 col = X_2_COL(beval->x);
46 }
47#endif
Bram Moolenaarb3d17a22019-07-07 18:28:14 +020048 if (find_word_under_cursor(row, col, getword,
49 FIND_IDENT + FIND_STRING + FIND_EVAL,
50 winp, lnump, textp, colp) == OK)
51 {
52#ifdef FEAT_VARTABS
53 vim_free(beval->vts);
54 beval->vts = tabstop_copy((*winp)->w_buffer->b_p_vts_array);
55 if ((*winp)->w_buffer->b_p_vts_array != NULL && beval->vts == NULL)
56 {
57 if (getword)
58 vim_free(*textp);
59 return FAIL;
60 }
61#endif
62 beval->ts = (*winp)->w_buffer->b_p_ts;
63 return OK;
64 }
65
66 return FAIL;
67}
68
69/*
70 * Find text under the mouse position "row" / "col".
71 * If "getword" is TRUE the returned text in "*textp" is not the whole line but
72 * the relevant word in allocated memory.
73 * Return OK if found.
74 * Return FAIL if not found, no text at the mouse position.
75 */
76 int
77find_word_under_cursor(
78 int mouserow,
79 int mousecol,
80 int getword,
81 int flags, // flags for find_ident_at_pos()
82 win_T **winp, // can be NULL
83 linenr_T *lnump, // can be NULL
84 char_u **textp,
85 int *colp)
86{
87 int row = mouserow;
88 int col = mousecol;
89 win_T *wp;
90 char_u *lbuf;
91 linenr_T lnum;
92
93 *textp = NULL;
Bram Moolenaar451d4b52019-06-12 20:22:27 +020094 wp = mouse_find_win(&row, &col, FAIL_POPUP);
Bram Moolenaar1ad022a2017-12-03 18:20:32 +010095 if (wp != NULL && row >= 0 && row < wp->w_height && col < wp->w_width)
Bram Moolenaarc3719bd2017-11-18 22:13:31 +010096 {
Bram Moolenaarb3d17a22019-07-07 18:28:14 +020097 // Found a window and the cursor is in the text. Now find the line
98 // number.
Bram Moolenaarc3719bd2017-11-18 22:13:31 +010099 if (!mouse_comp_pos(wp, &row, &col, &lnum))
100 {
Bram Moolenaarb3d17a22019-07-07 18:28:14 +0200101 // Not past end of the file.
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100102 lbuf = ml_get_buf(wp->w_buffer, lnum, FALSE);
103 if (col <= win_linetabsize(wp, lbuf, (colnr_T)MAXCOL))
104 {
Bram Moolenaarb3d17a22019-07-07 18:28:14 +0200105 // Not past end of line.
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100106 if (getword)
107 {
Bram Moolenaarb3d17a22019-07-07 18:28:14 +0200108 // For Netbeans we get the relevant part of the line
109 // instead of the whole line.
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100110 int len;
111 pos_T *spos = NULL, *epos = NULL;
112
113 if (VIsual_active)
114 {
115 if (LT_POS(VIsual, curwin->w_cursor))
116 {
117 spos = &VIsual;
118 epos = &curwin->w_cursor;
119 }
120 else
121 {
122 spos = &curwin->w_cursor;
123 epos = &VIsual;
124 }
125 }
126
127 col = vcol2col(wp, lnum, col);
128
129 if (VIsual_active
130 && wp->w_buffer == curwin->w_buffer
131 && (lnum == spos->lnum
132 ? col >= (int)spos->col
133 : lnum > spos->lnum)
134 && (lnum == epos->lnum
135 ? col <= (int)epos->col
136 : lnum < epos->lnum))
137 {
Bram Moolenaarb3d17a22019-07-07 18:28:14 +0200138 // Visual mode and pointing to the line with the
139 // Visual selection: return selected text, with a
140 // maximum of one line.
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100141 if (spos->lnum != epos->lnum || spos->col == epos->col)
142 return FAIL;
143
144 lbuf = ml_get_buf(curwin->w_buffer, VIsual.lnum, FALSE);
145 len = epos->col - spos->col;
146 if (*p_sel != 'e')
147 len += MB_PTR2LEN(lbuf + epos->col);
148 lbuf = vim_strnsave(lbuf + spos->col, len);
149 lnum = spos->lnum;
150 col = spos->col;
151 }
152 else
153 {
Bram Moolenaarb3d17a22019-07-07 18:28:14 +0200154 // Find the word under the cursor.
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100155 ++emsg_off;
156 len = find_ident_at_pos(wp, lnum, (colnr_T)col, &lbuf,
Bram Moolenaarb3d17a22019-07-07 18:28:14 +0200157 flags);
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100158 --emsg_off;
159 if (len == 0)
160 return FAIL;
161 lbuf = vim_strnsave(lbuf, len);
162 }
163 }
164
Bram Moolenaarb3d17a22019-07-07 18:28:14 +0200165 if (winp != NULL)
166 *winp = wp;
167 if (lnump != NULL)
168 *lnump = lnum;
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100169 *textp = lbuf;
170 *colp = col;
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100171 return OK;
172 }
173 }
174 }
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100175 return FAIL;
176}
177
178/*
Bram Moolenaar246fe032017-11-19 19:56:27 +0100179 * Show a balloon with "mesg" or "list".
Bram Moolenaar451d4b52019-06-12 20:22:27 +0200180 * Hide the balloon when both are NULL.
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100181 */
182 void
Bram Moolenaar792f0e32018-02-27 17:27:13 +0100183post_balloon(BalloonEval *beval UNUSED, char_u *mesg, list_T *list UNUSED)
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100184{
185# ifdef FEAT_BEVAL_TERM
186# ifdef FEAT_GUI
187 if (!gui.in_use)
188# endif
Bram Moolenaar246fe032017-11-19 19:56:27 +0100189 ui_post_balloon(mesg, list);
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100190# endif
191# ifdef FEAT_BEVAL_GUI
192 if (gui.in_use)
Bram Moolenaar451d4b52019-06-12 20:22:27 +0200193 // GUI can't handle a list
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100194 gui_mch_post_balloon(beval, mesg);
195# endif
196}
197
198/*
199 * Returns TRUE if the balloon eval has been enabled:
200 * 'ballooneval' for the GUI and 'balloonevalterm' for the terminal.
201 * Also checks if the screen isn't scrolled up.
202 */
203 int
204can_use_beval(void)
205{
206 return (0
207#ifdef FEAT_BEVAL_GUI
208 || (gui.in_use && p_beval)
209#endif
210#ifdef FEAT_BEVAL_TERM
211 || (
212# ifdef FEAT_GUI
213 !gui.in_use &&
214# endif
215 p_bevalterm)
216#endif
217 ) && msg_scrolled == 0;
218}
219
220/*
221 * Common code, invoked when the mouse is resting for a moment.
222 */
223 void
224general_beval_cb(BalloonEval *beval, int state UNUSED)
225{
226#ifdef FEAT_EVAL
227 win_T *wp;
228 int col;
229 int use_sandbox;
230 linenr_T lnum;
231 char_u *text;
232 static char_u *result = NULL;
233 long winnr = 0;
234 char_u *bexpr;
235 buf_T *save_curbuf;
236 size_t len;
237 win_T *cw;
238#endif
239 static int recursive = FALSE;
240
241 /* Don't do anything when 'ballooneval' is off, messages scrolled the
242 * windows up or we have no beval area. */
243 if (!can_use_beval() || beval == NULL)
244 return;
245
246 /* Don't do this recursively. Happens when the expression evaluation
247 * takes a long time and invokes something that checks for CTRL-C typed. */
248 if (recursive)
249 return;
250 recursive = TRUE;
251
252#ifdef FEAT_EVAL
253 if (get_beval_info(beval, TRUE, &wp, &lnum, &text, &col) == OK)
254 {
255 bexpr = (*wp->w_buffer->b_p_bexpr == NUL) ? p_bexpr
256 : wp->w_buffer->b_p_bexpr;
257 if (*bexpr != NUL)
258 {
259 /* Convert window pointer to number. */
260 for (cw = firstwin; cw != wp; cw = cw->w_next)
261 ++winnr;
262
263 set_vim_var_nr(VV_BEVAL_BUFNR, (long)wp->w_buffer->b_fnum);
264 set_vim_var_nr(VV_BEVAL_WINNR, winnr);
265 set_vim_var_nr(VV_BEVAL_WINID, wp->w_id);
266 set_vim_var_nr(VV_BEVAL_LNUM, (long)lnum);
267 set_vim_var_nr(VV_BEVAL_COL, (long)(col + 1));
268 set_vim_var_string(VV_BEVAL_TEXT, text, -1);
269 vim_free(text);
270
271 /*
272 * Temporarily change the curbuf, so that we can determine whether
273 * the buffer-local balloonexpr option was set insecurely.
274 */
275 save_curbuf = curbuf;
276 curbuf = wp->w_buffer;
277 use_sandbox = was_set_insecurely((char_u *)"balloonexpr",
278 *curbuf->b_p_bexpr == NUL ? 0 : OPT_LOCAL);
279 curbuf = save_curbuf;
280 if (use_sandbox)
281 ++sandbox;
282 ++textlock;
283
284 vim_free(result);
285 result = eval_to_string(bexpr, NULL, TRUE);
286
287 /* Remove one trailing newline, it is added when the result was a
288 * list and it's hardly ever useful. If the user really wants a
289 * trailing newline he can add two and one remains. */
290 if (result != NULL)
291 {
292 len = STRLEN(result);
293 if (len > 0 && result[len - 1] == NL)
294 result[len - 1] = NUL;
295 }
296
297 if (use_sandbox)
298 --sandbox;
299 --textlock;
300
301 set_vim_var_string(VV_BEVAL_TEXT, NULL, -1);
302 if (result != NULL && result[0] != NUL)
303 {
Bram Moolenaar246fe032017-11-19 19:56:27 +0100304 post_balloon(beval, result, NULL);
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100305 recursive = FALSE;
306 return;
307 }
308 }
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