xref: /vim-8.2.3635/src/beval.c (revision 12ee7ff0)
1 /* 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
22 get_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
52     wp = mouse_find_win(&row, &col);
53     if (wp != NULL && row >= 0 && row < wp->w_height && col < wp->w_width)
54     {
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;
127 #ifdef FEAT_VARTABS
128 		vim_free(beval->vts);
129 		beval->vts = tabstop_copy(wp->w_buffer->b_p_vts_array);
130 		if (wp->w_buffer->b_p_vts_array != NULL && beval->vts == NULL)
131 		    return FAIL;
132 #endif
133 		beval->ts = wp->w_buffer->b_p_ts;
134 		return OK;
135 	    }
136 	}
137     }
138 
139     return FAIL;
140 }
141 
142 /*
143  * Show a balloon with "mesg" or "list".
144  */
145     void
146 post_balloon(BalloonEval *beval UNUSED, char_u *mesg, list_T *list UNUSED)
147 {
148 # ifdef FEAT_BEVAL_TERM
149 #  ifdef FEAT_GUI
150     if (!gui.in_use)
151 #  endif
152 	ui_post_balloon(mesg, list);
153 # endif
154 # ifdef FEAT_BEVAL_GUI
155     if (gui.in_use)
156 	/* GUI can't handle a list */
157 	gui_mch_post_balloon(beval, mesg);
158 # endif
159 }
160 
161 /*
162  * Returns TRUE if the balloon eval has been enabled:
163  * 'ballooneval' for the GUI and 'balloonevalterm' for the terminal.
164  * Also checks if the screen isn't scrolled up.
165  */
166     int
167 can_use_beval(void)
168 {
169     return (0
170 #ifdef FEAT_BEVAL_GUI
171 		|| (gui.in_use && p_beval)
172 #endif
173 #ifdef FEAT_BEVAL_TERM
174 		|| (
175 # ifdef FEAT_GUI
176 		    !gui.in_use &&
177 # endif
178 		    p_bevalterm)
179 #endif
180 	     ) && msg_scrolled == 0;
181 }
182 
183 /*
184  * Common code, invoked when the mouse is resting for a moment.
185  */
186     void
187 general_beval_cb(BalloonEval *beval, int state UNUSED)
188 {
189 #ifdef FEAT_EVAL
190     win_T	*wp;
191     int		col;
192     int		use_sandbox;
193     linenr_T	lnum;
194     char_u	*text;
195     static char_u  *result = NULL;
196     long	winnr = 0;
197     char_u	*bexpr;
198     buf_T	*save_curbuf;
199     size_t	len;
200     win_T	*cw;
201 #endif
202     static int	recursive = FALSE;
203 
204     /* Don't do anything when 'ballooneval' is off, messages scrolled the
205      * windows up or we have no beval area. */
206     if (!can_use_beval() || beval == NULL)
207 	return;
208 
209     /* Don't do this recursively.  Happens when the expression evaluation
210      * takes a long time and invokes something that checks for CTRL-C typed. */
211     if (recursive)
212 	return;
213     recursive = TRUE;
214 
215 #ifdef FEAT_EVAL
216     if (get_beval_info(beval, TRUE, &wp, &lnum, &text, &col) == OK)
217     {
218 	bexpr = (*wp->w_buffer->b_p_bexpr == NUL) ? p_bexpr
219 						    : wp->w_buffer->b_p_bexpr;
220 	if (*bexpr != NUL)
221 	{
222 	    /* Convert window pointer to number. */
223 	    for (cw = firstwin; cw != wp; cw = cw->w_next)
224 		++winnr;
225 
226 	    set_vim_var_nr(VV_BEVAL_BUFNR, (long)wp->w_buffer->b_fnum);
227 	    set_vim_var_nr(VV_BEVAL_WINNR, winnr);
228 	    set_vim_var_nr(VV_BEVAL_WINID, wp->w_id);
229 	    set_vim_var_nr(VV_BEVAL_LNUM, (long)lnum);
230 	    set_vim_var_nr(VV_BEVAL_COL, (long)(col + 1));
231 	    set_vim_var_string(VV_BEVAL_TEXT, text, -1);
232 	    vim_free(text);
233 
234 	    /*
235 	     * Temporarily change the curbuf, so that we can determine whether
236 	     * the buffer-local balloonexpr option was set insecurely.
237 	     */
238 	    save_curbuf = curbuf;
239 	    curbuf = wp->w_buffer;
240 	    use_sandbox = was_set_insecurely((char_u *)"balloonexpr",
241 				 *curbuf->b_p_bexpr == NUL ? 0 : OPT_LOCAL);
242 	    curbuf = save_curbuf;
243 	    if (use_sandbox)
244 		++sandbox;
245 	    ++textlock;
246 
247 	    vim_free(result);
248 	    result = eval_to_string(bexpr, NULL, TRUE);
249 
250 	    /* Remove one trailing newline, it is added when the result was a
251 	     * list and it's hardly ever useful.  If the user really wants a
252 	     * trailing newline he can add two and one remains. */
253 	    if (result != NULL)
254 	    {
255 		len = STRLEN(result);
256 		if (len > 0 && result[len - 1] == NL)
257 		    result[len - 1] = NUL;
258 	    }
259 
260 	    if (use_sandbox)
261 		--sandbox;
262 	    --textlock;
263 
264 	    set_vim_var_string(VV_BEVAL_TEXT, NULL, -1);
265 	    if (result != NULL && result[0] != NUL)
266 	    {
267 		post_balloon(beval, result, NULL);
268 		recursive = FALSE;
269 		return;
270 	    }
271 	}
272     }
273 #endif
274 #ifdef FEAT_NETBEANS_INTG
275     if (bevalServers & BEVAL_NETBEANS)
276 	netbeans_beval_cb(beval, state);
277 #endif
278 
279     recursive = FALSE;
280 }
281 
282 #endif
283 
284