diff options
Diffstat (limited to 'src/beval.c')
-rw-r--r-- | src/beval.c | 326 |
1 files changed, 326 insertions, 0 deletions
diff --git a/src/beval.c b/src/beval.c new file mode 100644 index 0000000..dd7bc3c --- /dev/null +++ b/src/beval.c @@ -0,0 +1,326 @@ +/* vi:set ts=8 sts=4 sw=4 noet: + * + * VIM - Vi IMproved by Bram Moolenaar + * Visual Workshop integration by Gordon Prieur + * + * Do ":help uganda" in Vim to read copying and usage conditions. + * Do ":help credits" in Vim to see a list of people who contributed. + * See README.txt for an overview of the Vim source code. + */ + +#include "vim.h" + +#if defined(FEAT_BEVAL) || defined(FEAT_PROP_POPUP) || defined(PROTO) +/* + * Find text under the mouse position "row" / "col". + * If "getword" is TRUE the returned text in "*textp" is not the whole line but + * the relevant word in allocated memory. + * Return OK if found. + * Return FAIL if not found, no text at the mouse position. + */ + int +find_word_under_cursor( + int mouserow, + int mousecol, + int getword, + int flags, // flags for find_ident_at_pos() + win_T **winp, // can be NULL + linenr_T *lnump, // can be NULL + char_u **textp, + int *colp, // column where mouse hovers, can be NULL + int *startcolp) // column where text starts, can be NULL +{ + int row = mouserow; + int col = mousecol; + int scol; + win_T *wp; + char_u *lbuf; + linenr_T lnum; + + *textp = NULL; + wp = mouse_find_win(&row, &col, FAIL_POPUP); + if (wp != NULL && row >= 0 && row < wp->w_height && col < wp->w_width) + { + // Found a window and the cursor is in the text. Now find the line + // number. + if (!mouse_comp_pos(wp, &row, &col, &lnum, NULL)) + { + // Not past end of the file. + lbuf = ml_get_buf(wp->w_buffer, lnum, FALSE); + if (col <= win_linetabsize(wp, lbuf, (colnr_T)MAXCOL)) + { + // Not past end of line. + if (getword) + { + // For Netbeans we get the relevant part of the line + // instead of the whole line. + int len; + pos_T *spos = NULL, *epos = NULL; + + if (VIsual_active) + { + if (LT_POS(VIsual, curwin->w_cursor)) + { + spos = &VIsual; + epos = &curwin->w_cursor; + } + else + { + spos = &curwin->w_cursor; + epos = &VIsual; + } + } + + col = vcol2col(wp, lnum, col); + scol = col; + + if (VIsual_active + && wp->w_buffer == curwin->w_buffer + && (lnum == spos->lnum + ? col >= (int)spos->col + : lnum > spos->lnum) + && (lnum == epos->lnum + ? col <= (int)epos->col + : lnum < epos->lnum)) + { + // Visual mode and pointing to the line with the + // Visual selection: return selected text, with a + // maximum of one line. + if (spos->lnum != epos->lnum || spos->col == epos->col) + return FAIL; + + lbuf = ml_get_buf(curwin->w_buffer, VIsual.lnum, FALSE); + len = epos->col - spos->col; + if (*p_sel != 'e') + len += mb_ptr2len(lbuf + epos->col); + lbuf = vim_strnsave(lbuf + spos->col, len); + lnum = spos->lnum; + col = spos->col; + scol = col; + } + else + { + // Find the word under the cursor. + ++emsg_off; + len = find_ident_at_pos(wp, lnum, (colnr_T)col, + &lbuf, &scol, flags); + --emsg_off; + if (len == 0) + return FAIL; + lbuf = vim_strnsave(lbuf, len); + } + } + else + scol = col; + + if (winp != NULL) + *winp = wp; + if (lnump != NULL) + *lnump = lnum; + *textp = lbuf; + if (colp != NULL) + *colp = col; + if (startcolp != NULL) + *startcolp = scol; + return OK; + } + } + } + return FAIL; +} +#endif + +#if defined(FEAT_BEVAL) || defined(PROTO) + +/* + * Get the text and position to be evaluated for "beval". + * If "getword" is TRUE the returned text is not the whole line but the + * relevant word in allocated memory. + * Returns OK or FAIL. + */ + int +get_beval_info( + BalloonEval *beval, + int getword, + win_T **winp, + linenr_T *lnump, + char_u **textp, + int *colp) +{ + int row = mouse_row; + int col = mouse_col; + +# ifdef FEAT_GUI + if (gui.in_use) + { + row = Y_2_ROW(beval->y); + col = X_2_COL(beval->x); + } +#endif + if (find_word_under_cursor(row, col, getword, + FIND_IDENT + FIND_STRING + FIND_EVAL, + winp, lnump, textp, colp, NULL) == OK) + { +#ifdef FEAT_VARTABS + vim_free(beval->vts); + beval->vts = tabstop_copy((*winp)->w_buffer->b_p_vts_array); + if ((*winp)->w_buffer->b_p_vts_array != NULL && beval->vts == NULL) + { + if (getword) + vim_free(*textp); + return FAIL; + } +#endif + beval->ts = (*winp)->w_buffer->b_p_ts; + return OK; + } + + return FAIL; +} + +/* + * Show a balloon with "mesg" or "list". + * Hide the balloon when both are NULL. + */ + void +post_balloon(BalloonEval *beval UNUSED, char_u *mesg, list_T *list UNUSED) +{ +# ifdef FEAT_BEVAL_TERM +# ifdef FEAT_GUI + if (!gui.in_use) +# endif + ui_post_balloon(mesg, list); +# endif +# ifdef FEAT_BEVAL_GUI + if (gui.in_use) + // GUI can't handle a list + gui_mch_post_balloon(beval, mesg); +# endif +} + +/* + * Returns TRUE if the balloon eval has been enabled: + * 'ballooneval' for the GUI and 'balloonevalterm' for the terminal. + * Also checks if the screen isn't scrolled up. + */ + int +can_use_beval(void) +{ + return (0 +#ifdef FEAT_BEVAL_GUI + || (gui.in_use && p_beval) +#endif +#ifdef FEAT_BEVAL_TERM + || ( +# ifdef FEAT_GUI + !gui.in_use && +# endif + p_bevalterm) +#endif + ) && msg_scrolled == 0; +} + +/* + * Common code, invoked when the mouse is resting for a moment. + */ + void +general_beval_cb(BalloonEval *beval, int state UNUSED) +{ +#ifdef FEAT_EVAL + win_T *wp; + int col; + int use_sandbox; + linenr_T lnum; + char_u *text; + static char_u *result = NULL; + long winnr = 0; + char_u *bexpr; + buf_T *save_curbuf; + size_t len; + win_T *cw; +#endif + static int recursive = FALSE; + + // Don't do anything when 'ballooneval' is off, messages scrolled the + // windows up or we have no beval area. + if (!can_use_beval() || beval == NULL) + return; + + // Don't do this recursively. Happens when the expression evaluation + // takes a long time and invokes something that checks for CTRL-C typed. + if (recursive) + return; + recursive = TRUE; + +#ifdef FEAT_EVAL + if (get_beval_info(beval, TRUE, &wp, &lnum, &text, &col) == OK) + { + bexpr = (*wp->w_buffer->b_p_bexpr == NUL) ? p_bexpr + : wp->w_buffer->b_p_bexpr; + if (*bexpr != NUL) + { + // Convert window pointer to number. + for (cw = firstwin; cw != wp; cw = cw->w_next) + ++winnr; + + set_vim_var_nr(VV_BEVAL_BUFNR, (long)wp->w_buffer->b_fnum); + set_vim_var_nr(VV_BEVAL_WINNR, winnr); + set_vim_var_nr(VV_BEVAL_WINID, wp->w_id); + set_vim_var_nr(VV_BEVAL_LNUM, (long)lnum); + set_vim_var_nr(VV_BEVAL_COL, (long)(col + 1)); + set_vim_var_string(VV_BEVAL_TEXT, text, -1); + vim_free(text); + + /* + * Temporarily change the curbuf, so that we can determine whether + * the buffer-local balloonexpr option was set insecurely. + */ + save_curbuf = curbuf; + curbuf = wp->w_buffer; + use_sandbox = was_set_insecurely((char_u *)"balloonexpr", + *curbuf->b_p_bexpr == NUL ? 0 : OPT_LOCAL); + curbuf = save_curbuf; + if (use_sandbox) + ++sandbox; + ++textwinlock; + + vim_free(result); + result = eval_to_string(bexpr, TRUE); + + // Remove one trailing newline, it is added when the result was a + // list and it's hardly ever useful. If the user really wants a + // trailing newline he can add two and one remains. + if (result != NULL) + { + len = STRLEN(result); + if (len > 0 && result[len - 1] == NL) + result[len - 1] = NUL; + } + + if (use_sandbox) + --sandbox; + --textwinlock; + + set_vim_var_string(VV_BEVAL_TEXT, NULL, -1); + if (result != NULL && result[0] != NUL) + post_balloon(beval, result, NULL); + + // The 'balloonexpr' evaluation may show something on the screen + // that requires a screen update. + if (must_redraw) + redraw_after_callback(FALSE); + + recursive = FALSE; + return; + } + } +#endif +#ifdef FEAT_NETBEANS_INTG + if (bevalServers & BEVAL_NETBEANS) + netbeans_beval_cb(beval, state); +#endif + + recursive = FALSE; +} + +#endif |