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