blob: e89b1fe50b57cc08f246968df1e5aeb6b26273ad [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".
17 * If "getword" is true the returned text is not the whole line but the
18 * 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{
30 win_T *wp;
31 int row, col;
32 char_u *lbuf;
33 linenr_T lnum;
34
35 *textp = NULL;
36# ifdef FEAT_BEVAL_TERM
37# ifdef FEAT_GUI
38 if (!gui.in_use)
39# endif
40 {
41 row = mouse_row;
42 col = mouse_col;
43 }
44# endif
45# ifdef FEAT_GUI
46 if (gui.in_use)
47 {
48 row = Y_2_ROW(beval->y);
49 col = X_2_COL(beval->x);
50 }
51#endif
Bram Moolenaar451d4b52019-06-12 20:22:27 +020052 wp = mouse_find_win(&row, &col, FAIL_POPUP);
Bram Moolenaar1ad022a2017-12-03 18:20:32 +010053 if (wp != NULL && row >= 0 && row < wp->w_height && col < wp->w_width)
Bram Moolenaarc3719bd2017-11-18 22:13:31 +010054 {
55 /* Found a window and the cursor is in the text. Now find the line
56 * number. */
57 if (!mouse_comp_pos(wp, &row, &col, &lnum))
58 {
59 /* Not past end of the file. */
60 lbuf = ml_get_buf(wp->w_buffer, lnum, FALSE);
61 if (col <= win_linetabsize(wp, lbuf, (colnr_T)MAXCOL))
62 {
63 /* Not past end of line. */
64 if (getword)
65 {
66 /* For Netbeans we get the relevant part of the line
67 * instead of the whole line. */
68 int len;
69 pos_T *spos = NULL, *epos = NULL;
70
71 if (VIsual_active)
72 {
73 if (LT_POS(VIsual, curwin->w_cursor))
74 {
75 spos = &VIsual;
76 epos = &curwin->w_cursor;
77 }
78 else
79 {
80 spos = &curwin->w_cursor;
81 epos = &VIsual;
82 }
83 }
84
85 col = vcol2col(wp, lnum, col);
86
87 if (VIsual_active
88 && wp->w_buffer == curwin->w_buffer
89 && (lnum == spos->lnum
90 ? col >= (int)spos->col
91 : lnum > spos->lnum)
92 && (lnum == epos->lnum
93 ? col <= (int)epos->col
94 : lnum < epos->lnum))
95 {
96 /* Visual mode and pointing to the line with the
97 * Visual selection: return selected text, with a
98 * maximum of one line. */
99 if (spos->lnum != epos->lnum || spos->col == epos->col)
100 return FAIL;
101
102 lbuf = ml_get_buf(curwin->w_buffer, VIsual.lnum, FALSE);
103 len = epos->col - spos->col;
104 if (*p_sel != 'e')
105 len += MB_PTR2LEN(lbuf + epos->col);
106 lbuf = vim_strnsave(lbuf + spos->col, len);
107 lnum = spos->lnum;
108 col = spos->col;
109 }
110 else
111 {
112 /* Find the word under the cursor. */
113 ++emsg_off;
114 len = find_ident_at_pos(wp, lnum, (colnr_T)col, &lbuf,
115 FIND_IDENT + FIND_STRING + FIND_EVAL);
116 --emsg_off;
117 if (len == 0)
118 return FAIL;
119 lbuf = vim_strnsave(lbuf, len);
120 }
121 }
122
123 *winp = wp;
124 *lnump = lnum;
125 *textp = lbuf;
126 *colp = col;
Bram Moolenaar04958cb2018-06-23 19:23:02 +0200127#ifdef FEAT_VARTABS
Bram Moolenaar54ade9f2018-10-02 14:15:12 +0200128 vim_free(beval->vts);
Bram Moolenaar04958cb2018-06-23 19:23:02 +0200129 beval->vts = tabstop_copy(wp->w_buffer->b_p_vts_array);
Bram Moolenaar6ee96582019-04-27 22:06:37 +0200130 if (wp->w_buffer->b_p_vts_array != NULL && beval->vts == NULL)
131 return FAIL;
Bram Moolenaar04958cb2018-06-23 19:23:02 +0200132#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100133 beval->ts = wp->w_buffer->b_p_ts;
134 return OK;
135 }
136 }
137 }
138
139 return FAIL;
140}
141
142/*
Bram Moolenaar246fe032017-11-19 19:56:27 +0100143 * Show a balloon with "mesg" or "list".
Bram Moolenaar451d4b52019-06-12 20:22:27 +0200144 * Hide the balloon when both are NULL.
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100145 */
146 void
Bram Moolenaar792f0e32018-02-27 17:27:13 +0100147post_balloon(BalloonEval *beval UNUSED, char_u *mesg, list_T *list UNUSED)
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100148{
149# ifdef FEAT_BEVAL_TERM
150# ifdef FEAT_GUI
151 if (!gui.in_use)
152# endif
Bram Moolenaar246fe032017-11-19 19:56:27 +0100153 ui_post_balloon(mesg, list);
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100154# endif
155# ifdef FEAT_BEVAL_GUI
156 if (gui.in_use)
Bram Moolenaar451d4b52019-06-12 20:22:27 +0200157 // GUI can't handle a list
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100158 gui_mch_post_balloon(beval, mesg);
159# endif
160}
161
162/*
163 * Returns TRUE if the balloon eval has been enabled:
164 * 'ballooneval' for the GUI and 'balloonevalterm' for the terminal.
165 * Also checks if the screen isn't scrolled up.
166 */
167 int
168can_use_beval(void)
169{
170 return (0
171#ifdef FEAT_BEVAL_GUI
172 || (gui.in_use && p_beval)
173#endif
174#ifdef FEAT_BEVAL_TERM
175 || (
176# ifdef FEAT_GUI
177 !gui.in_use &&
178# endif
179 p_bevalterm)
180#endif
181 ) && msg_scrolled == 0;
182}
183
184/*
185 * Common code, invoked when the mouse is resting for a moment.
186 */
187 void
188general_beval_cb(BalloonEval *beval, int state UNUSED)
189{
190#ifdef FEAT_EVAL
191 win_T *wp;
192 int col;
193 int use_sandbox;
194 linenr_T lnum;
195 char_u *text;
196 static char_u *result = NULL;
197 long winnr = 0;
198 char_u *bexpr;
199 buf_T *save_curbuf;
200 size_t len;
201 win_T *cw;
202#endif
203 static int recursive = FALSE;
204
205 /* Don't do anything when 'ballooneval' is off, messages scrolled the
206 * windows up or we have no beval area. */
207 if (!can_use_beval() || beval == NULL)
208 return;
209
210 /* Don't do this recursively. Happens when the expression evaluation
211 * takes a long time and invokes something that checks for CTRL-C typed. */
212 if (recursive)
213 return;
214 recursive = TRUE;
215
216#ifdef FEAT_EVAL
217 if (get_beval_info(beval, TRUE, &wp, &lnum, &text, &col) == OK)
218 {
219 bexpr = (*wp->w_buffer->b_p_bexpr == NUL) ? p_bexpr
220 : wp->w_buffer->b_p_bexpr;
221 if (*bexpr != NUL)
222 {
223 /* Convert window pointer to number. */
224 for (cw = firstwin; cw != wp; cw = cw->w_next)
225 ++winnr;
226
227 set_vim_var_nr(VV_BEVAL_BUFNR, (long)wp->w_buffer->b_fnum);
228 set_vim_var_nr(VV_BEVAL_WINNR, winnr);
229 set_vim_var_nr(VV_BEVAL_WINID, wp->w_id);
230 set_vim_var_nr(VV_BEVAL_LNUM, (long)lnum);
231 set_vim_var_nr(VV_BEVAL_COL, (long)(col + 1));
232 set_vim_var_string(VV_BEVAL_TEXT, text, -1);
233 vim_free(text);
234
235 /*
236 * Temporarily change the curbuf, so that we can determine whether
237 * the buffer-local balloonexpr option was set insecurely.
238 */
239 save_curbuf = curbuf;
240 curbuf = wp->w_buffer;
241 use_sandbox = was_set_insecurely((char_u *)"balloonexpr",
242 *curbuf->b_p_bexpr == NUL ? 0 : OPT_LOCAL);
243 curbuf = save_curbuf;
244 if (use_sandbox)
245 ++sandbox;
246 ++textlock;
247
248 vim_free(result);
249 result = eval_to_string(bexpr, NULL, TRUE);
250
251 /* Remove one trailing newline, it is added when the result was a
252 * list and it's hardly ever useful. If the user really wants a
253 * trailing newline he can add two and one remains. */
254 if (result != NULL)
255 {
256 len = STRLEN(result);
257 if (len > 0 && result[len - 1] == NL)
258 result[len - 1] = NUL;
259 }
260
261 if (use_sandbox)
262 --sandbox;
263 --textlock;
264
265 set_vim_var_string(VV_BEVAL_TEXT, NULL, -1);
266 if (result != NULL && result[0] != NUL)
267 {
Bram Moolenaar246fe032017-11-19 19:56:27 +0100268 post_balloon(beval, result, NULL);
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100269 recursive = FALSE;
270 return;
271 }
272 }
273 }
274#endif
275#ifdef FEAT_NETBEANS_INTG
276 if (bevalServers & BEVAL_NETBEANS)
277 netbeans_beval_cb(beval, state);
278#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100279
280 recursive = FALSE;
281}
282
283#endif
284