diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index a0a3e332ff..39341c2701 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -5228,6 +5228,7 @@ getwininfo([{winid}]) *getwininfo()* tab pages is returned. Each List item is a Dictionary with the following entries: + botline last displayed buffer line bufnr number of buffer in the window height window height (excluding winbar) loclist 1 if showing a location list @@ -5237,6 +5238,7 @@ getwininfo([{winid}]) *getwininfo()* terminal 1 if a terminal window {only with the +terminal feature} tabnr tab page number + topline first displayed buffer line variables a reference to the dictionary with window-local variables width window width diff --git a/src/buffer.c b/src/buffer.c index 537140fcd8..d2aed73f22 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -2167,11 +2167,9 @@ free_buf_options( clear_string_option(&buf->b_p_isk); #ifdef FEAT_VARTABS clear_string_option(&buf->b_p_vsts); - if (buf->b_p_vsts_nopaste) - vim_free(buf->b_p_vsts_nopaste); + vim_free(buf->b_p_vsts_nopaste); buf->b_p_vsts_nopaste = NULL; - if (buf->b_p_vsts_array) - vim_free(buf->b_p_vsts_array); + vim_free(buf->b_p_vsts_array); buf->b_p_vsts_array = NULL; clear_string_option(&buf->b_p_vts); VIM_CLEAR(buf->b_p_vts_array); diff --git a/src/channel.c b/src/channel.c index 2d565bd839..a6208e04a8 100644 --- a/src/channel.c +++ b/src/channel.c @@ -1823,6 +1823,7 @@ channel_consume(channel_T *channel, ch_part_T part, int len) mch_memmove(buf, buf + len, node->rq_buflen - len); node->rq_buflen -= len; + node->rq_buffer[node->rq_buflen] = NUL; } /* @@ -1845,7 +1846,7 @@ channel_collapse(channel_T *channel, ch_part_T part, int want_nl) return FAIL; last_node = node->rq_next; - len = node->rq_buflen + last_node->rq_buflen + 1; + len = node->rq_buflen + last_node->rq_buflen; if (want_nl) while (last_node->rq_next != NULL && channel_first_nl(last_node) == NULL) @@ -1854,7 +1855,7 @@ channel_collapse(channel_T *channel, ch_part_T part, int want_nl) len += last_node->rq_buflen; } - p = newbuf = alloc(len); + p = newbuf = alloc(len + 1); if (newbuf == NULL) return FAIL; /* out of memory */ mch_memmove(p, node->rq_buffer, node->rq_buflen); @@ -1868,6 +1869,7 @@ channel_collapse(channel_T *channel, ch_part_T part, int want_nl) p += n->rq_buflen; vim_free(n->rq_buffer); } + *p = NUL; node->rq_buflen = (long_u)(p - newbuf); /* dispose of the collapsed nodes and their buffers */ @@ -2692,30 +2694,20 @@ may_invoke_callback(channel_T *channel, ch_part_T part) } buf = node->rq_buffer; - if (nl == NULL) - { - /* Flush remaining message that is missing a NL. */ - char_u *new_buf; - - new_buf = vim_realloc(buf, node->rq_buflen + 1); - if (new_buf == NULL) - /* This might fail over and over again, should the message - * be dropped? */ - return FALSE; - buf = new_buf; - node->rq_buffer = buf; - nl = buf + node->rq_buflen++; - *nl = NUL; - } - - /* Convert NUL to NL, the internal representation. */ - for (p = buf; p < nl && p < buf + node->rq_buflen; ++p) + // Convert NUL to NL, the internal representation. + for (p = buf; (nl == NULL || p < nl) + && p < buf + node->rq_buflen; ++p) if (*p == NUL) *p = NL; - if (nl + 1 == buf + node->rq_buflen) + if (nl == NULL) { - /* get the whole buffer, drop the NL */ + // get the whole buffer, drop the NL + msg = channel_get(channel, part, NULL); + } + else if (nl + 1 == buf + node->rq_buflen) + { + // get the whole buffer msg = channel_get(channel, part, NULL); *nl = NUL; } diff --git a/src/crypt.c b/src/crypt.c index 47617e9a9c..e9c52aa143 100644 --- a/src/crypt.c +++ b/src/crypt.c @@ -42,7 +42,7 @@ typedef struct { /* Optional function pointer for a self-test. */ int (* self_test_fn)(); - /* Function pointer for initializing encryption/decription. */ + // Function pointer for initializing encryption/description. void (* init_fn)(cryptstate_T *state, char_u *key, char_u *salt, int salt_len, char_u *seed, int seed_len); diff --git a/src/diff.c b/src/diff.c index 336157c6d9..38ae0b47c9 100644 --- a/src/diff.c +++ b/src/diff.c @@ -866,7 +866,11 @@ theend: int diff_internal(void) { - return (diff_flags & DIFF_INTERNAL) != 0 && *p_dex == NUL; + return (diff_flags & DIFF_INTERNAL) != 0 +#ifdef FEAT_EVAL + && *p_dex == NUL +#endif + ; } /* diff --git a/src/eval.c b/src/eval.c index 046688f0b8..9e1ac6d993 100644 --- a/src/eval.c +++ b/src/eval.c @@ -253,6 +253,39 @@ static char_u *find_option_end(char_u **arg, int *opt_flags); /* for VIM_VERSION_ defines */ #include "version.h" +/* + * Return "n1" divided by "n2", taking care of dividing by zero. + */ + static varnumber_T +num_divide(varnumber_T n1, varnumber_T n2) +{ + varnumber_T result; + + if (n2 == 0) // give an error message? + { + if (n1 == 0) + result = VARNUM_MIN; // similar to NaN + else if (n1 < 0) + result = -VARNUM_MAX; + else + result = VARNUM_MAX; + } + else + result = n1 / n2; + + return result; +} + +/* + * Return "n1" modulus "n2", taking care of dividing by zero. + */ + static varnumber_T +num_modulus(varnumber_T n1, varnumber_T n2) +{ + // Give an error when n2 is 0? + return (n2 == 0) ? 0 : (n1 % n2); +} + #if defined(EBCDIC) || defined(PROTO) /* @@ -1758,8 +1791,8 @@ ex_let_one( case '+': n = numval + n; break; case '-': n = numval - n; break; case '*': n = numval * n; break; - case '/': n = numval / n; break; - case '%': n = numval % n; break; + case '/': n = (long)num_divide(numval, n); break; + case '%': n = (long)num_modulus(numval, n); break; } } else if (opt_type == 0 && stringval != NULL) // string @@ -2538,8 +2571,8 @@ tv_op(typval_T *tv1, typval_T *tv2, char_u *op) case '+': n += tv_get_number(tv2); break; case '-': n -= tv_get_number(tv2); break; case '*': n *= tv_get_number(tv2); break; - case '/': n /= tv_get_number(tv2); break; - case '%': n %= tv_get_number(tv2); break; + case '/': n = num_divide(n, tv_get_number(tv2)); break; + case '%': n = num_modulus(n, tv_get_number(tv2)); break; } clear_tv(tv1); tv1->v_type = VAR_NUMBER; @@ -4113,26 +4146,10 @@ eval6( if (op == '*') n1 = n1 * n2; else if (op == '/') - { - if (n2 == 0) /* give an error message? */ - { - if (n1 == 0) - n1 = VARNUM_MIN; /* similar to NaN */ - else if (n1 < 0) - n1 = -VARNUM_MAX; - else - n1 = VARNUM_MAX; - } - else - n1 = n1 / n2; - } + n1 = num_divide(n1, n2); else - { - if (n2 == 0) /* give an error message? */ - n1 = 0; - else - n1 = n1 % n2; - } + n1 = num_modulus(n1, n2); + rettv->v_type = VAR_NUMBER; rettv->vval.v_number = n1; } diff --git a/src/evalfunc.c b/src/evalfunc.c index ff62a01cf1..47c7598178 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -2451,7 +2451,7 @@ f_char2nr(typval_T *argvars, typval_T *rettv) utf8 = (int)tv_get_number_chk(&argvars[1], NULL); if (utf8) - rettv->vval.v_number = (*utf_ptr2char)(tv_get_string(&argvars[0])); + rettv->vval.v_number = utf_ptr2char(tv_get_string(&argvars[0])); else rettv->vval.v_number = (*mb_ptr2char)(tv_get_string(&argvars[0])); } @@ -4811,6 +4811,7 @@ f_getchar(typval_T *argvars, typval_T *rettv) { varnumber_T n; int error = FALSE; + int save_reg_executing = reg_executing; #ifdef MESSAGE_QUEUE // vpeekc() used to check for messages, but that caused problems, invoking @@ -4845,6 +4846,7 @@ f_getchar(typval_T *argvars, typval_T *rettv) } --no_mapping; --allow_keys; + reg_executing = save_reg_executing; set_vim_var_nr(VV_MOUSE_WIN, 0); set_vim_var_nr(VV_MOUSE_WINID, 0); @@ -5480,9 +5482,23 @@ getpos_both( (varnumber_T)0); if (getcurpos) { + int save_set_curswant = curwin->w_set_curswant; + colnr_T save_curswant = curwin->w_curswant; + colnr_T save_virtcol = curwin->w_virtcol; + update_curswant(); list_append_number(l, curwin->w_curswant == MAXCOL ? (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1); + + // Do not change "curswant", as it is unexpected that a get + // function has a side effect. + if (save_set_curswant) + { + curwin->w_set_curswant = save_set_curswant; + curwin->w_curswant = save_curswant; + curwin->w_virtcol = save_virtcol; + curwin->w_valid &= ~VALID_VIRTCOL; + } } } else @@ -5770,6 +5786,8 @@ get_win_info(win_T *wp, short tpnr, short winnr) dict_add_number(dict, "winid", wp->w_id); dict_add_number(dict, "height", wp->w_height); dict_add_number(dict, "winrow", wp->w_winrow + 1); + dict_add_number(dict, "topline", wp->w_topline); + dict_add_number(dict, "botline", wp->w_botline - 1); #ifdef FEAT_MENU dict_add_number(dict, "winbar", wp->w_winbar_height); #endif @@ -6163,7 +6181,7 @@ f_has(typval_T *argvars, typval_T *rettv) #ifdef MSWIN "win32", #endif -#if defined(UNIX) && (defined(__CYGWIN32__) || defined(__CYGWIN__)) +#if defined(UNIX) && defined(__CYGWIN__) "win32unix", #endif #ifdef _WIN64 @@ -8724,7 +8742,7 @@ f_nr2char(typval_T *argvars, typval_T *rettv) if (argvars[1].v_type != VAR_UNKNOWN) utf8 = (int)tv_get_number_chk(&argvars[1], NULL); if (utf8) - buf[(*utf_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL; + buf[utf_char2bytes((int)tv_get_number(&argvars[0]), buf)] = NUL; else buf[(*mb_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL; } @@ -11678,7 +11696,7 @@ f_sign_jump(typval_T *argvars, typval_T *rettv) rettv->vval.v_number = -1; - // Sign identifer + // Sign identifier sign_id = (int)tv_get_number_chk(&argvars[0], ¬anum); if (notanum) return; @@ -11730,7 +11748,7 @@ f_sign_place(typval_T *argvars, typval_T *rettv) rettv->vval.v_number = -1; - // Sign identifer + // Sign identifier sign_id = (int)tv_get_number_chk(&argvars[0], ¬anum); if (notanum) return; diff --git a/src/ex_cmds2.c b/src/ex_cmds2.c index 2add538047..a915db7a47 100644 --- a/src/ex_cmds2.c +++ b/src/ex_cmds2.c @@ -2453,7 +2453,7 @@ check_changed_any( goto_tabpage_win(tp, wp); - /* Paranoia: did autocms wipe out the buffer with changes? */ + // Paranoia: did autocmd wipe out the buffer with changes? if (!bufref_valid(&bufref)) goto theend; goto buf_found; diff --git a/src/ex_docmd.c b/src/ex_docmd.c index df0bcd31a9..3832f74af9 100644 --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -10286,6 +10286,7 @@ save_current_state(save_state_T *sst) sst->save_insertmode = p_im; sst->save_finish_op = finish_op; sst->save_opcount = opcount; + sst->save_reg_executing = reg_executing; msg_scroll = FALSE; /* no msg scrolling in Normal mode */ restart_edit = 0; /* don't go to Insert mode */ @@ -10311,6 +10312,7 @@ restore_current_state(save_state_T *sst) p_im = sst->save_insertmode; finish_op = sst->save_finish_op; opcount = sst->save_opcount; + reg_executing = sst->save_reg_executing; msg_didout |= sst->save_msg_didout; /* don't reset msg_didout now */ /* Restore the state (needed when called from a function executed for diff --git a/src/globals.h b/src/globals.h index 975736e332..e543f51d68 100644 --- a/src/globals.h +++ b/src/globals.h @@ -426,7 +426,7 @@ EXTERN int mouse_dragging INIT(= 0); /* extending Visual area with # if defined(FEAT_MOUSE_DEC) /* * When the DEC mouse has been pressed but not yet released we enable - * automatic querys for the mouse position. + * automatic queries for the mouse position. */ EXTERN int WantQueryMouse INIT(= FALSE); # endif diff --git a/src/gui_gtk_f.c b/src/gui_gtk_f.c index d81474b3f7..6146fe6d9e 100644 --- a/src/gui_gtk_f.c +++ b/src/gui_gtk_f.c @@ -561,7 +561,7 @@ gtk_form_draw(GtkWidget *widget, cairo_t *cr) * gtk_widget_size_allocate() in advance with a well-posed * allocation for a given child widget in order to set a * certain private GtkWidget variable, called - * widget->priv->alloc_need, to the proper value; othewise, + * widget->priv->alloc_need, to the proper value; otherwise, * gtk_widget_draw() fails and the relevant scrollbar won't * appear on the screen. * diff --git a/src/gui_gtk_x11.c b/src/gui_gtk_x11.c index 5e74adcebe..5275026f88 100644 --- a/src/gui_gtk_x11.c +++ b/src/gui_gtk_x11.c @@ -7015,7 +7015,7 @@ gui_mch_drawsign(int row, int col, int typenr) (double)(MIN(height, SIGN_HEIGHT))) < 1.15) { /* Change the aspect ratio by at most 15% to fill the - * available space completly. */ + * available space completely. */ height = (double)SIGN_HEIGHT * SIGN_ASPECT / aspect; height = MIN(height, SIGN_HEIGHT); } diff --git a/src/gui_mac.c b/src/gui_mac.c index a004ff1ee4..5034215f2e 100644 --- a/src/gui_mac.c +++ b/src/gui_mac.c @@ -1342,10 +1342,6 @@ InstallAEHandlers(void) } error = AEInstallEventHandler('KAHL', 'MOD ', NewAEEventHandlerUPP(Handle_KAHL_MOD_AE), 0, false); - if (error) - { - return error; - } #endif return error; diff --git a/src/if_perl.xs b/src/if_perl.xs index 2655640755..099d386776 100644 --- a/src/if_perl.xs +++ b/src/if_perl.xs @@ -1570,7 +1570,7 @@ Blob(SV* sv) newsv = newSVpv("0z", 2); for (i = 0; i < len; i++) { - sprintf(buf, "%02X", s[i]); + sprintf(buf, "%02X", (unsigned char)(s[i])); sv_catpvn(newsv, buf, 2); } RETVAL = newsv; diff --git a/src/if_ruby.c b/src/if_ruby.c index d3ed781281..543ee8ac27 100644 --- a/src/if_ruby.c +++ b/src/if_ruby.c @@ -1267,7 +1267,7 @@ static VALUE vim_blob(VALUE self UNUSED, VALUE str) int i; for (i = 0; i < RSTRING_LEN(str); i++) { - sprintf(buf, "%02X", RSTRING_PTR(str)[i]); + sprintf(buf, "%02X", (unsigned char)(RSTRING_PTR(str)[i])); rb_str_concat(result, rb_str_new2(buf)); } return result; diff --git a/src/ops.c b/src/ops.c index c5e2be5e53..3353cf9e26 100644 --- a/src/ops.c +++ b/src/ops.c @@ -1747,7 +1747,6 @@ op_delete(oparg_T *oap) struct block_def bd; linenr_T old_lcount = curbuf->b_ml.ml_line_count; int did_yank = FALSE; - int orig_regname = oap->regname; if (curbuf->b_ml.ml_flags & ML_EMPTY) /* nothing to do */ return OK; @@ -1833,12 +1832,13 @@ op_delete(oparg_T *oap) /* * Put deleted text into register 1 and shift number registers if the - * delete contains a line break, or when a regname has been specified. + * delete contains a line break, or when using a specific operator (Vi + * compatible) * Use the register name from before adjust_clip_reg() may have * changed it. */ - if (orig_regname != 0 || oap->motion_type == MLINE - || oap->line_count > 1 || oap->use_reg_one) + if (oap->motion_type == MLINE || oap->line_count > 1 + || oap->use_reg_one) { shift_delete_registers(); if (op_yank(oap, TRUE, FALSE) == OK) @@ -5402,7 +5402,7 @@ op_addsub( linenr_T amount = Prenum1; // do_addsub() might trigger re-evaluation of 'foldexpr' halfway, when the - // buffer is not completly updated yet. Postpone updating folds until before + // buffer is not completely updated yet. Postpone updating folds until before // the call to changed_lines(). #ifdef FEAT_FOLDING disable_fold_update++; diff --git a/src/option.h b/src/option.h index 834c8fb6c6..3bebbb2bf8 100644 --- a/src/option.h +++ b/src/option.h @@ -193,8 +193,8 @@ #define SHM_WRI 'w' /* "[w]" instead of "written" */ #define SHM_A "rmfixlnw" /* represented by 'a' flag */ #define SHM_WRITE 'W' /* don't use "written" at all */ -#define SHM_TRUNC 't' /* trunctate file messages */ -#define SHM_TRUNCALL 'T' /* trunctate all messages */ +#define SHM_TRUNC 't' /* truncate file messages */ +#define SHM_TRUNCALL 'T' /* truncate all messages */ #define SHM_OVER 'o' /* overwrite file messages */ #define SHM_OVERALL 'O' /* overwrite more messages */ #define SHM_SEARCH 's' /* no search hit bottom messages */ diff --git a/src/os_unix.c b/src/os_unix.c index e085a174c4..5d22721a48 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -1605,7 +1605,7 @@ x_IOerror_check(Display *dpy UNUSED) { /* This function should not return, it causes exit(). Longjump instead. */ LONGJMP(lc_jump_env, 1); -# if defined(VMS) || defined(__CYGWIN__) || defined(__CYGWIN32__) +# if defined(VMS) || defined(__CYGWIN__) return 0; /* avoid the compiler complains about missing return value */ # endif } @@ -1627,7 +1627,7 @@ x_IOerror_handler(Display *dpy UNUSED) /* This function should not return, it causes exit(). Longjump instead. */ LONGJMP(x_jump_env, 1); -# if defined(VMS) || defined(__CYGWIN__) || defined(__CYGWIN32__) +# if defined(VMS) || defined(__CYGWIN__) return 0; /* avoid the compiler complains about missing return value */ # endif } @@ -6440,7 +6440,7 @@ mch_expand_wildcards( int shell_style = STYLE_ECHO; int check_spaces; static int did_find_nul = FALSE; - int ampersent = FALSE; + int ampersand = FALSE; /* vimglob() function to define for Posix shell */ static char *sh_vimglob_func = "vimglob() { while [ $# -ge 1 ]; do echo \"$1\"; shift; done }; vimglob >"; @@ -6557,7 +6557,7 @@ mch_expand_wildcards( --p; if (*p == '&') /* remove trailing '&' */ { - ampersent = TRUE; + ampersand = TRUE; *p = ' '; } STRCAT(command, ">"); @@ -6626,7 +6626,7 @@ mch_expand_wildcards( } if (flags & EW_SILENT) show_shell_mess = FALSE; - if (ampersent) + if (ampersand) STRCAT(command, "&"); /* put the '&' after the redirection */ /* @@ -6652,7 +6652,7 @@ mch_expand_wildcards( /* When running in the background, give it some time to create the temp * file, but don't wait for it to finish. */ - if (ampersent) + if (ampersand) mch_delay(10L, TRUE); extra_shell_arg = NULL; /* cleanup */ @@ -6735,7 +6735,7 @@ mch_expand_wildcards( } vim_free(tempname); -# if defined(__CYGWIN__) || defined(__CYGWIN32__) +# ifdef __CYGWIN__ /* Translate into . Caution, buffer may contain NUL. */ p = buffer; for (i = 0; i < (int)len; ++i) diff --git a/src/os_unix.h b/src/os_unix.h index 8919ff0fa1..5df943c70b 100644 --- a/src/os_unix.h +++ b/src/os_unix.h @@ -33,7 +33,7 @@ # include #endif -#if defined(__CYGWIN__) || defined(__CYGWIN32__) +#ifdef __CYGWIN__ # define WIN32UNIX /* Compiling for Win32 using Unix files. */ # define BINARY_FILE_IO diff --git a/src/os_win32.c b/src/os_win32.c index b9233156ea..876a7a409a 100644 --- a/src/os_win32.c +++ b/src/os_win32.c @@ -2094,8 +2094,8 @@ executable_exists(char *name, char_u **path, int use_path) return TRUE; } -#if ((defined(__MINGW32__) || defined (__CYGWIN32__)) && \ - __MSVCRT_VERSION__ >= 0x800) || (defined(_MSC_VER) && _MSC_VER >= 1400) +#if (defined(__MINGW32__) && __MSVCRT_VERSION__ >= 0x800) || \ + (defined(_MSC_VER) && _MSC_VER >= 1400) /* * Bad parameter handler. * @@ -2646,7 +2646,7 @@ mch_init(void) if (cterm_normal_bg_color == 0) cterm_normal_bg_color = ((g_attrCurrent >> 4) & 0xf) + 1; - // Fg and Bg color index nunmber at startup + // Fg and Bg color index number at startup g_color_index_fg = g_attrDefault & 0xf; g_color_index_bg = (g_attrDefault >> 4) & 0xf; @@ -4210,8 +4210,7 @@ vim_create_process( (LPSTARTUPINFOW)si, /* Startup information */ pi); /* Process information */ vim_free(wcmd); - if (wcwd != NULL) - vim_free(wcwd); + vim_free(wcwd); return ret; } fallback: @@ -5312,8 +5311,8 @@ win32_build_env(dict_T *env, garray_T *gap, int is_terminal) *((WCHAR*)gap->ga_data + gap->ga_len++) = wval[n]; *((WCHAR*)gap->ga_data + gap->ga_len++) = L'\0'; } - if (wkey != NULL) vim_free(wkey); - if (wval != NULL) vim_free(wval); + vim_free(wkey); + vim_free(wval); } } } @@ -7845,7 +7844,7 @@ set_console_color_rgb(void) return; id = syn_name2id((char_u *)"Normal"); - if (id > 0) + if (id > 0 && p_tgc) syn_id2colors(id, &fg, &bg); if (fg == INVALCOLOR) { diff --git a/src/popupmnu.c b/src/popupmnu.c index 755dba45a6..7be8a9be41 100644 --- a/src/popupmnu.c +++ b/src/popupmnu.c @@ -405,7 +405,7 @@ pum_redraw(void) char_u *p = NULL; int totwidth, width, w; int thumb_pos = 0; - int thumb_heigth = 1; + int thumb_height = 1; int round; int n; @@ -423,10 +423,10 @@ pum_redraw(void) if (pum_scrollbar) { - thumb_heigth = pum_height * pum_height / pum_size; - if (thumb_heigth == 0) - thumb_heigth = 1; - thumb_pos = (pum_first * (pum_height - thumb_heigth) + thumb_height = pum_height * pum_height / pum_size; + if (thumb_height == 0) + thumb_height = 1; + thumb_pos = (pum_first * (pum_height - thumb_height) + (pum_size - pum_height) / 2) / (pum_size - pum_height); } @@ -600,12 +600,12 @@ pum_redraw(void) #ifdef FEAT_RIGHTLEFT if (curwin->w_p_rl) screen_putchar(' ', row, pum_col - pum_width, - i >= thumb_pos && i < thumb_pos + thumb_heigth + i >= thumb_pos && i < thumb_pos + thumb_height ? attr_thumb : attr_scroll); else #endif screen_putchar(' ', row, pum_col + pum_width, - i >= thumb_pos && i < thumb_pos + thumb_heigth + i >= thumb_pos && i < thumb_pos + thumb_height ? attr_thumb : attr_scroll); } diff --git a/src/quickfix.c b/src/quickfix.c index ea2e8c9d18..2053c45a68 100644 --- a/src/quickfix.c +++ b/src/quickfix.c @@ -3980,6 +3980,27 @@ qf_goto_cwindow(qf_info_T *qi, int resize, int sz, int vertsplit) return OK; } +/* + * Set options for the buffer in the quickfix or location list window. + */ + static void +qf_set_cwindow_options(void) +{ + // switch off 'swapfile' + set_option_value((char_u *)"swf", 0L, NULL, OPT_LOCAL); + set_option_value((char_u *)"bt", 0L, (char_u *)"quickfix", + OPT_LOCAL); + set_option_value((char_u *)"bh", 0L, (char_u *)"hide", OPT_LOCAL); + RESET_BINDING(curwin); +#ifdef FEAT_DIFF + curwin->w_p_diff = FALSE; +#endif +#ifdef FEAT_FOLDING + set_option_value((char_u *)"fdm", 0L, (char_u *)"manual", + OPT_LOCAL); +#endif +} + /* * Open a new quickfix or location list window, load the quickfix buffer and * set the appropriate options for the window. @@ -4032,23 +4053,16 @@ qf_open_new_cwindow(qf_info_T *qi, int height) // Create a new quickfix buffer (void)do_ecmd(0, NULL, NULL, NULL, ECMD_ONE, ECMD_HIDE, oldwin); - // switch off 'swapfile' - set_option_value((char_u *)"swf", 0L, NULL, OPT_LOCAL); - set_option_value((char_u *)"bt", 0L, (char_u *)"quickfix", - OPT_LOCAL); - set_option_value((char_u *)"bh", 0L, (char_u *)"hide", OPT_LOCAL); - RESET_BINDING(curwin); -#ifdef FEAT_DIFF - curwin->w_p_diff = FALSE; -#endif -#ifdef FEAT_FOLDING - set_option_value((char_u *)"fdm", 0L, (char_u *)"manual", - OPT_LOCAL); -#endif // save the number of the new buffer qi->qf_bufnr = curbuf->b_fnum; } + // Set the options for the quickfix buffer/window (if not already done) + // Do this even if the quickfix buffer was already present, as an autocmd + // might have previously deleted (:bdelete) the quickfix buffer. + if (curbuf->b_p_bt[0] != 'q') + qf_set_cwindow_options(); + // Only set the height when still in the same tab page and there is no // window to the side. if (curtab == prevtab && curwin->w_width == Columns) diff --git a/src/regexp.c b/src/regexp.c index 5c06ada1b7..4b853172e5 100644 --- a/src/regexp.c +++ b/src/regexp.c @@ -2228,7 +2228,7 @@ regatom(int *flagp) default: i = -1; break; } - if (i < 0) + if (i < 0 || i > INT_MAX) EMSG2_RET_NULL( _("E678: Invalid character after %s%%[dxouU]"), reg_magic == MAGIC_ALL); @@ -3293,7 +3293,7 @@ coll_get_char(void) case 'u': nr = gethexchrs(4); break; case 'U': nr = gethexchrs(8); break; } - if (nr < 0) + if (nr < 0 || nr > INT_MAX) { /* If getting the number fails be backwards compatible: the character * is a backslash. */ @@ -6457,7 +6457,7 @@ regdump(char_u *pattern, bt_regprog_T *r) } else if (op == RE_LNUM || op == RE_COL || op == RE_VCOL) { - /* one int plus comperator */ + /* one int plus comparator */ fprintf(f, " count %ld", OPERAND_MIN(s)); s += 5; } diff --git a/src/screen.c b/src/screen.c index 89d2e501e4..b56fa5f71a 100644 --- a/src/screen.c +++ b/src/screen.c @@ -836,7 +836,7 @@ update_screen(int type_arg) return OK; } -#if defined(FEAT_SIGNS) || defined(FEAT_GUI) || defined(FEAT_CONCEAL) +#if defined(FEAT_NETBEANS_INTG) || defined(FEAT_GUI) /* * Prepare for updating one or more windows. * Caller must check for "updating_screen" already set to avoid recursiveness. diff --git a/src/search.c b/src/search.c index 7a20d83777..7edade9f98 100644 --- a/src/search.c +++ b/src/search.c @@ -576,7 +576,9 @@ set_last_search_pat( saved_spats[idx].pat = NULL; else saved_spats[idx].pat = vim_strsave(spats[idx].pat); +# ifdef FEAT_SEARCH_EXTRA saved_spats_last_idx = last_idx; +# endif } # ifdef FEAT_SEARCH_EXTRA /* If 'hlsearch' set and search pat changed: need redraw. */ diff --git a/src/structs.h b/src/structs.h index 54e55433fd..78620f51c0 100644 --- a/src/structs.h +++ b/src/structs.h @@ -2637,19 +2637,19 @@ typedef struct w_line */ struct frame_S { - char fr_layout; /* FR_LEAF, FR_COL or FR_ROW */ + char fr_layout; // FR_LEAF, FR_COL or FR_ROW int fr_width; - int fr_newwidth; /* new width used in win_equal_rec() */ + int fr_newwidth; // new width used in win_equal_rec() int fr_height; - int fr_newheight; /* new height used in win_equal_rec() */ - frame_T *fr_parent; /* containing frame or NULL */ - frame_T *fr_next; /* frame right or below in same parent, NULL - for first */ - frame_T *fr_prev; /* frame left or above in same parent, NULL - for last */ - /* fr_child and fr_win are mutually exclusive */ - frame_T *fr_child; /* first contained frame */ - win_T *fr_win; /* window that fills this frame */ + int fr_newheight; // new height used in win_equal_rec() + frame_T *fr_parent; // containing frame or NULL + frame_T *fr_next; // frame right or below in same parent, NULL + // for last + frame_T *fr_prev; // frame left or above in same parent, NULL + // for first + // fr_child and fr_win are mutually exclusive + frame_T *fr_child; // first contained frame + win_T *fr_win; // window that fills this frame }; #define FR_LEAF 0 /* frame is a leaf */ @@ -3546,6 +3546,7 @@ typedef struct { int save_insertmode; int save_finish_op; int save_opcount; + int save_reg_executing; tasave_T tabuf; } save_state_T; diff --git a/src/terminal.c b/src/terminal.c index cc6e967960..e1ce97d8df 100644 --- a/src/terminal.c +++ b/src/terminal.c @@ -3270,7 +3270,6 @@ update_system_term(term_T *term) term->tl_dirty_row_start = MAX_ROW; term->tl_dirty_row_end = 0; - update_cursor(term, TRUE); } #endif diff --git a/src/testdir/Make_all.mak b/src/testdir/Make_all.mak index 7cc5e7eae6..774c96b7a4 100644 --- a/src/testdir/Make_all.mak +++ b/src/testdir/Make_all.mak @@ -212,6 +212,7 @@ NEW_TESTS = \ test_regexp_utf8 \ test_registers \ test_reltime \ + test_rename \ test_restricted \ test_retab \ test_ruby \ diff --git a/src/testdir/dumps/Test_incsearch_substitute_11.dump b/src/testdir/dumps/Test_incsearch_substitute_11.dump index 0ec409f01a..cc401be54c 100644 --- a/src/testdir/dumps/Test_incsearch_substitute_11.dump +++ b/src/testdir/dumps/Test_incsearch_substitute_11.dump @@ -2,8 +2,8 @@ |f+0&#ffff4012|o@1| |2| +0&#ffffff0@64 |f+0&#ffff4012|o@1| |3| +0&#ffffff0@64 |[+3&&|N|o| |N|a|m|e|]| |[|+|]| @38|1|,|1| @11|T|o|p -|f+0&#ffff4012|o@1| |1| +0&#ffffff0@64 |f+0&#ffff4012|o@1| |2| +0&#ffffff0@64 |f+0&#ffff4012|o@1| |3| +0&#ffffff0@64 -|[+1&&|N|o| |N|a|m|e|]| |[|+|]| @38|2|,|1| @11|T|o|p +|f+0&#ffff4012|o@1| |4| +0&#ffffff0@64 +|[+1&&|N|o| |N|a|m|e|]| |[|+|]| @38|2|,|1| @11|1|2|% |:+0&&|%|s|/|.> @64 diff --git a/src/testdir/dumps/Test_incsearch_substitute_12.dump b/src/testdir/dumps/Test_incsearch_substitute_12.dump index 02b73355dc..80c4e152f1 100644 --- a/src/testdir/dumps/Test_incsearch_substitute_12.dump +++ b/src/testdir/dumps/Test_incsearch_substitute_12.dump @@ -1,9 +1,9 @@ -|f+0&#ffffff0|o@1| |1| @64 -|f|o@1| |2| @64 +|f+0&#ffffff0|o@1| |2| @64 |f|o@1| |3| @64 +|f|o@1| |4| @64 |[+3&&|N|o| |N|a|m|e|]| |[|+|]| @38|1|,|1| @11|T|o|p -|f+0&&|o@1| |1| @64 -|f|o@1| |2| @64 +|f+0&&|o@1| |2| @64 |f|o@1| |3| @64 -|[+1&&|N|o| |N|a|m|e|]| |[|+|]| @38|2|,|1| @11|T|o|p +|f|o@1| |4| @64 +|[+1&&|N|o| |N|a|m|e|]| |[|+|]| @38|2|,|1| @11|1|2|% |:+0&&|%|s|/> @65 diff --git a/src/testdir/dumps/Test_incsearch_substitute_13.dump b/src/testdir/dumps/Test_incsearch_substitute_13.dump index be3abb7121..32feb55cb6 100644 --- a/src/testdir/dumps/Test_incsearch_substitute_13.dump +++ b/src/testdir/dumps/Test_incsearch_substitute_13.dump @@ -1,9 +1,9 @@ -|f+0&#ffffff0|o@1| |1| @64 ->f|o@1| |2| @64 +>f+0&#ffffff0|o@1| |2| @64 |f|o@1| |3| @64 -|[+3&&|N|o| |N|a|m|e|]| |[|+|]| @38|2|,|1| @11|T|o|p -|f+0&&|o@1| |1| @64 -|f|o@1| |2| @64 +|f|o@1| |4| @64 +|[+3&&|N|o| |N|a|m|e|]| |[|+|]| @38|2|,|1| @11|1|2|% +|f+0&&|o@1| |2| @64 |f|o@1| |3| @64 -|[+1&&|N|o| |N|a|m|e|]| |[|+|]| @38|2|,|1| @11|T|o|p +|f|o@1| |4| @64 +|[+1&&|N|o| |N|a|m|e|]| |[|+|]| @38|2|,|1| @11|1|2|% | +0&&@69 diff --git a/src/testdir/test_alot.vim b/src/testdir/test_alot.vim index 204796a971..47fe5be8a2 100644 --- a/src/testdir/test_alot.vim +++ b/src/testdir/test_alot.vim @@ -48,6 +48,7 @@ source test_popup.vim source test_put.vim source test_recover.vim source test_reltime.vim +source test_rename.vim source test_scroll_opt.vim source test_searchpos.vim source test_set.vim diff --git a/src/testdir/test_channel.vim b/src/testdir/test_channel.vim index 67163e606b..2f2b5597fb 100644 --- a/src/testdir/test_channel.vim +++ b/src/testdir/test_channel.vim @@ -203,8 +203,7 @@ func Ch_communicate(port) let start = reltime() call assert_equal(v:none, ch_read(handle, {'timeout': 333})) let elapsed = reltime(start) - call assert_true(reltimefloat(elapsed) > 0.3) - call assert_true(reltimefloat(elapsed) < 0.6) + call assert_inrange(0.3, 0.6, reltimefloat(reltime(start))) " Send without waiting for a response, then wait for a response. call ch_sendexpr(handle, 'wait a bit') @@ -434,9 +433,7 @@ func Test_connect_waittime() else " Failed connection should wait about 500 msec. Can be longer if the " computer is busy with other things. - let elapsed = reltime(start) - call assert_true(reltimefloat(elapsed) > 0.3) - call assert_true(reltimefloat(elapsed) < 1.5) + call assert_inrange(0.3, 1.5, reltimefloat(reltime(start))) endif catch if v:exception !~ 'Connection reset by peer' @@ -1590,8 +1587,7 @@ func Test_exit_callback_interval() else let elapsed = 1.0 endif - call assert_true(elapsed > 0.5) - call assert_true(elapsed < 1.0) + call assert_inrange(0.5, 1.0, elapsed) endfunc """"""""" @@ -1764,10 +1760,6 @@ func Test_raw_passes_nul() bwipe! endfunc -func MyLineCountCb(ch, msg) - let g:linecount += 1 -endfunc - func Test_read_nonl_line() if !has('job') return @@ -1775,8 +1767,28 @@ func Test_read_nonl_line() let g:linecount = 0 let arg = 'import sys;sys.stdout.write("1\n2\n3")' - call job_start([s:python, '-c', arg], {'callback': 'MyLineCountCb'}) + call job_start([s:python, '-c', arg], {'callback': {-> execute('let g:linecount += 1')}}) call WaitForAssert({-> assert_equal(3, g:linecount)}) + unlet g:linecount +endfunc + +func Test_read_nonl_in_close_cb() + if !has('job') + return + endif + + func s:close_cb(ch) + while ch_status(a:ch) == 'buffered' + let g:out .= ch_read(a:ch) + endwhile + endfunc + + let g:out = '' + let arg = 'import sys;sys.stdout.write("1\n2\n3")' + call job_start([s:python, '-c', arg], {'close_cb': function('s:close_cb')}) + call WaitForAssert({-> assert_equal('123', g:out)}) + unlet g:out + delfunc s:close_cb endfunc func Test_read_from_terminated_job() @@ -1786,8 +1798,9 @@ func Test_read_from_terminated_job() let g:linecount = 0 let arg = 'import os,sys;os.close(1);sys.stderr.write("test\n")' - call job_start([s:python, '-c', arg], {'callback': 'MyLineCountCb'}) + call job_start([s:python, '-c', arg], {'callback': {-> execute('let g:linecount += 1')}}) call WaitForAssert({-> assert_equal(1, g:linecount)}) + unlet g:linecount endfunc func Test_job_start_windows() diff --git a/src/testdir/test_functions.vim b/src/testdir/test_functions.vim index a7caf22408..d53499950e 100644 --- a/src/testdir/test_functions.vim +++ b/src/testdir/test_functions.vim @@ -1137,6 +1137,34 @@ func Test_reg_executing_and_recording() call feedkeys("q\"\"=s:save_reg_stat()\pq", 'xt') call assert_equal('":', s:reg_stat) + " :normal command saves and restores reg_executing + let s:reg_stat = '' + let @q = ":call TestFunc()\:call s:save_reg_stat()\" + func TestFunc() abort + normal! ia + endfunc + call feedkeys("@q", 'xt') + call assert_equal(':q', s:reg_stat) + delfunc TestFunc + + " getchar() command saves and restores reg_executing + map W :call TestFunc() + let @q = "W" + func TestFunc() abort + let g:reg1 = reg_executing() + let g:typed = getchar(0) + let g:reg2 = reg_executing() + endfunc + call feedkeys("@qy", 'xt') + call assert_equal(char2nr("y"), g:typed) + call assert_equal('q', g:reg1) + call assert_equal('q', g:reg2) + delfunc TestFunc + unmap W + unlet g:typed + unlet g:reg1 + unlet g:reg2 + bwipe! delfunc s:save_reg_stat unlet s:reg_stat diff --git a/src/testdir/test_listdict.vim b/src/testdir/test_listdict.vim index 4807d78245..9064245219 100644 --- a/src/testdir/test_listdict.vim +++ b/src/testdir/test_listdict.vim @@ -641,19 +641,69 @@ func Test_listdict_compare_complex() endfunc func Test_listdict_extend() + " Test extend() with lists + " Pass the same List to extend() - let l = [1, 2, 3, 4, 5] - call extend(l, l) - call assert_equal([1, 2, 3, 4, 5, 1, 2, 3, 4, 5], l) + let l = [1, 2, 3] + call assert_equal([1, 2, 3, 1, 2, 3], extend(l, l)) + call assert_equal([1, 2, 3, 1, 2, 3], l) + + let l = [1, 2, 3] + call assert_equal([1, 2, 3, 4, 5, 6], extend(l, [4, 5, 6])) + call assert_equal([1, 2, 3, 4, 5, 6], l) + + let l = [1, 2, 3] + call extend(l, [4, 5, 6], 0) + call assert_equal([4, 5, 6, 1, 2, 3], l) + + let l = [1, 2, 3] + call extend(l, [4, 5, 6], 1) + call assert_equal([1, 4, 5, 6, 2, 3], l) + + let l = [1, 2, 3] + call extend(l, [4, 5, 6], 3) + call assert_equal([1, 2, 3, 4, 5, 6], l) + + let l = [1, 2, 3] + call extend(l, [4, 5, 6], -1) + call assert_equal([1, 2, 4, 5, 6, 3], l) + + let l = [1, 2, 3] + call extend(l, [4, 5, 6], -3) + call assert_equal([4, 5, 6, 1, 2, 3], l) + + let l = [1, 2, 3] + call assert_fails("call extend(l, [4, 5, 6], 4)", 'E684:') + call assert_fails("call extend(l, [4, 5, 6], -4)", 'E684:') + call assert_fails("call extend(l, [4, 5, 6], 1.2)", 'E805:') + + " Test extend() with dictionaries. " Pass the same Dict to extend() let d = { 'a': {'b': 'B'}} call extend(d, d) call assert_equal({'a': {'b': 'B'}}, d) - " Pass the same Dict to extend() with "error" - call assert_fails("call extend(d, d, 'error')", 'E737:') - call assert_equal({'a': {'b': 'B'}}, d) + let d = {'a': 'A', 'b': 'B'} + call assert_equal({'a': 'A', 'b': 0, 'c': 'C'}, extend(d, {'b': 0, 'c':'C'})) + call assert_equal({'a': 'A', 'b': 0, 'c': 'C'}, d) + + let d = {'a': 'A', 'b': 'B'} + call extend(d, {'a': 'A', 'b': 0, 'c': 'C'}, "force") + call assert_equal({'a': 'A', 'b': 0, 'c': 'C'}, d) + + let d = {'a': 'A', 'b': 'B'} + call extend(d, {'b': 0, 'c':'C'}, "keep") + call assert_equal({'a': 'A', 'b': 'B', 'c': 'C'}, d) + + let d = {'a': 'A', 'b': 'B'} + call assert_fails("call extend(d, {'b': 0, 'c':'C'}, 'error')", 'E737:') + call assert_fails("call extend(d, {'b': 0, 'c':'C'}, 'xxx')", 'E475:') + call assert_fails("call extend(d, {'b': 0, 'c':'C'}, 1.2)", 'E806:') + call assert_equal({'a': 'A', 'b': 'B'}, d) + + call assert_fails("call extend([1, 2], 1)", 'E712:') + call assert_fails("call extend([1, 2], {})", 'E712:') endfunc func s:check_scope_dict(x, fixed) diff --git a/src/testdir/test_perl.vim b/src/testdir/test_perl.vim index 03c5fa0d10..e24c04f7ce 100644 --- a/src/testdir/test_perl.vim +++ b/src/testdir/test_perl.vim @@ -29,6 +29,13 @@ EOF call assert_equal('abc/def/', getline('$')) endfunc +funct Test_VIM_Blob() + call assert_equal('0z', perleval('VIM::Blob("")')) + call assert_equal('0z31326162', perleval('VIM::Blob("12ab")')) + call assert_equal('0z00010203', perleval('VIM::Blob("\x00\x01\x02\x03")')) + call assert_equal('0z8081FEFF', perleval('VIM::Blob("\x80\x81\xfe\xff")')) +endfunc + func Test_buffer_Delete() new call setline(1, ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']) diff --git a/src/testdir/test_quickfix.vim b/src/testdir/test_quickfix.vim index d31bd5233f..4213975d8f 100644 --- a/src/testdir/test_quickfix.vim +++ b/src/testdir/test_quickfix.vim @@ -3933,6 +3933,16 @@ func Xqfbuf_test(cchar) call assert_match(qfbnum . ' h- "\[Location List]"', execute('ls')) call assert_true(bufloaded(qfbnum)) + " After deleting a location list buffer using ":bdelete", opening the + " location list window should mark the buffer as a location list buffer. + exe "bdelete " . qfbnum + lopen + call assert_equal("quickfix", &buftype) + call assert_equal(1, getwininfo(win_getid(winnr()))[0].loclist) + call assert_equal(wid, getloclist(0, {'filewinid' : 0}).filewinid) + call assert_false(&swapfile) + lclose + " When the location list is cleared for the window, the buffer should be " removed call setloclist(0, [], 'f') diff --git a/src/testdir/test_registers.vim b/src/testdir/test_registers.vim index d7b6de5652..1ed0a66d1e 100644 --- a/src/testdir/test_registers.vim +++ b/src/testdir/test_registers.vim @@ -42,7 +42,6 @@ func Test_display_registers() call assert_match('^\n--- Registers ---\n' \ . '"" a\n' \ . '"0 ba\n' - \ . '"1 b\n' \ . '"a b\n' \ . '.*' \ . '"- a\n' @@ -63,3 +62,87 @@ func Test_display_registers() bwipe! endfunc + +func Test_register_one() + " delete a line goes into register one + new + call setline(1, "one") + normal dd + call assert_equal("one\n", @1) + + " delete a word does not change register one, does change "- + call setline(1, "two") + normal de + call assert_equal("one\n", @1) + call assert_equal("two", @-) + + " delete a word with a register does not change register one + call setline(1, "three") + normal "ade + call assert_equal("three", @a) + call assert_equal("one\n", @1) + + " delete a word with register DOES change register one with one of a list of + " operators + " % + call setline(1, ["(12)3"]) + normal "ad% + call assert_equal("(12)", @a) + call assert_equal("(12)", @1) + + " ( + call setline(1, ["first second"]) + normal $"ad( + call assert_equal("first secon", @a) + call assert_equal("first secon", @1) + + " ) + call setline(1, ["First Second."]) + normal gg0"ad) + call assert_equal("First Second.", @a) + call assert_equal("First Second.", @1) + + " ` + call setline(1, ["start here."]) + normal gg0fhmx0"ad`x + call assert_equal("start ", @a) + call assert_equal("start ", @1) + + " / + call setline(1, ["searchX"]) + exe "normal gg0\"ad/X\" + call assert_equal("search", @a) + call assert_equal("search", @1) + + " ? + call setline(1, ["Ysearch"]) + exe "normal gg$\"ad?Y\" + call assert_equal("Ysearc", @a) + call assert_equal("Ysearc", @1) + + " n + call setline(1, ["Ynext"]) + normal gg$"adn + call assert_equal("Ynex", @a) + call assert_equal("Ynex", @1) + + " N + call setline(1, ["prevY"]) + normal gg0"adN + call assert_equal("prev", @a) + call assert_equal("prev", @1) + + " } + call setline(1, ["one", ""]) + normal gg0"ad} + call assert_equal("one\n", @a) + call assert_equal("one\n", @1) + + " { + call setline(1, ["", "two"]) + normal 2G$"ad{ + call assert_equal("\ntw", @a) + call assert_equal("\ntw", @1) + + bwipe! +endfunc diff --git a/src/testdir/test_rename.vim b/src/testdir/test_rename.vim new file mode 100644 index 0000000000..2311caf790 --- /dev/null +++ b/src/testdir/test_rename.vim @@ -0,0 +1,118 @@ +" Test rename() + +func Test_rename_file_to_file() + call writefile(['foo'], 'Xrename1') + + call assert_equal(0, rename('Xrename1', 'Xrename2')) + + call assert_equal('', glob('Xrename1')) + call assert_equal(['foo'], readfile('Xrename2')) + + " When the destination file already exists, it should be overwritten. + call writefile(['foo'], 'Xrename1') + call writefile(['bar'], 'Xrename2') + + call assert_equal(0, rename('Xrename1', 'Xrename2')) + call assert_equal('', glob('Xrename1')) + call assert_equal(['foo'], readfile('Xrename2')) + + call delete('Xrename2') +endfunc + +func Test_rename_file_ignore_case() + " With 'fileignorecase', renaming file will go through a temp file + " when the source and destination file only differ by case. + set fileignorecase + call writefile(['foo'], 'Xrename') + + call assert_equal(0, rename('Xrename', 'XRENAME')) + + call assert_equal(['foo'], readfile('XRENAME')) + + set fileignorecase& + call delete('XRENAME') +endfunc + +func Test_rename_same_file() + call writefile(['foo'], 'Xrename') + + " When the source and destination are the same file, nothing + " should be done. The source file should not be deleted. + call assert_equal(0, rename('Xrename', 'Xrename')) + call assert_equal(['foo'], readfile('Xrename')) + + call assert_equal(0, rename('./Xrename', 'Xrename')) + call assert_equal(['foo'], readfile('Xrename')) + + call delete('Xrename') +endfunc + +func Test_rename_dir_to_dir() + call mkdir('Xrenamedir1') + call writefile(['foo'], 'Xrenamedir1/Xrenamefile') + + call assert_equal(0, rename('Xrenamedir1', 'Xrenamedir2')) + + call assert_equal('', glob('Xrenamedir1')) + call assert_equal(['foo'], readfile('Xrenamedir2/Xrenamefile')) + + call delete('Xrenamedir2/Xrenamefile') + call delete('Xrenamedir2', 'd') +endfunc + +func Test_rename_same_dir() + call mkdir('Xrenamedir') + call writefile(['foo'], 'Xrenamedir/Xrenamefile') + + call assert_equal(0, rename('Xrenamedir', 'Xrenamedir')) + + call assert_equal(['foo'], readfile('Xrenamedir/Xrenamefile')) + + call delete('Xrenamedir/Xrenamefile') + call delete('Xrenamedir', 'd') +endfunc + +func Test_rename_copy() + " Check that when original file can't be deleted, rename() + " still succeeds but copies the file. + call mkdir('Xrenamedir') + call writefile(['foo'], 'Xrenamedir/Xrenamefile') + call setfperm('Xrenamedir', 'r-xr-xr-x') + + call assert_equal(0, rename('Xrenamedir/Xrenamefile', 'Xrenamefile')) + + if !has('win32') + " On Windows, the source file is removed despite + " its directory being made not writable. + call assert_equal(['foo'], readfile('Xrenamedir/Xrenamefile')) + endif + call assert_equal(['foo'], readfile('Xrenamefile')) + + call setfperm('Xrenamedir', 'rwxrwxrwx') + call delete('Xrenamedir/Xrenamefile') + call delete('Xrenamedir', 'd') + call delete('Xrenamefile') +endfunc + +func Test_rename_fails() + call writefile(['foo'], 'Xrenamefile') + + " Can't rename into a non-existing directory. + call assert_notequal(0, rename('Xrenamefile', 'Xdoesnotexist/Xrenamefile')) + + " Can't rename a non-existing file. + call assert_notequal(0, rename('Xdoesnotexist', 'Xrenamefile2')) + call assert_equal('', glob('Xrenamefile2')) + + " When rename() fails, the destination file should not be deleted. + call assert_notequal(0, rename('Xdoesnotexist', 'Xrenamefile')) + call assert_equal(['foo'], readfile('Xrenamefile')) + + " Can't rename to en empty file name. + call assert_notequal(0, rename('Xrenamefile', '')) + + call assert_fails('call rename("Xrenamefile", [])', 'E730') + call assert_fails('call rename(0z, "Xrenamefile")', 'E976') + + call delete('Xrenamefile') +endfunc diff --git a/src/testdir/test_ruby.vim b/src/testdir/test_ruby.vim index 5476e5171f..fe2afa6259 100644 --- a/src/testdir/test_ruby.vim +++ b/src/testdir/test_ruby.vim @@ -306,6 +306,9 @@ func Test_Vim_evaluate() call assert_equal('foo', RubyEval('Vim::evaluate("\"foo\"")')) call assert_equal('String', RubyEval('Vim::evaluate("\"foo\"").class')) + call assert_equal('["\x01\xAB"]', RubyEval('Vim::evaluate("0z01ab").unpack("M")')) + call assert_equal('String', RubyEval('Vim::evaluate("0z01ab").class')) + call assert_equal('[1, 2]', RubyEval('Vim::evaluate("[1, 2]")')) call assert_equal('Array', RubyEval('Vim::evaluate("[1, 2]").class')) @@ -324,6 +327,13 @@ func Test_Vim_evaluate() call assert_equal('FalseClass',RubyEval('Vim::evaluate("v:false").class')) endfunc +func Test_Vim_blob() + call assert_equal('0z', RubyEval('Vim::blob("")')) + call assert_equal('0z31326162', RubyEval('Vim::blob("12ab")')) + call assert_equal('0z00010203', RubyEval('Vim::blob("\x00\x01\x02\x03")')) + call assert_equal('0z8081FEFF', RubyEval('Vim::blob("\x80\x81\xfe\xff")')) +endfunc + func Test_Vim_evaluate_list() call setline(line('$'), ['2 line 2']) ruby Vim.command("normal /^2\n") diff --git a/src/testdir/test_search.vim b/src/testdir/test_search.vim index 5cf70d4d89..d32369d5a2 100644 --- a/src/testdir/test_search.vim +++ b/src/testdir/test_search.vim @@ -1212,13 +1212,36 @@ func Test_search_Ctrl_L_combining() call Incsearch_cleanup() endfunc -func Test_large_hex_chars() +func Test_large_hex_chars1() " This used to cause a crash, the character becomes an NFA state. try /\%Ufffffc23 catch call assert_match('E678:', v:exception) endtry + try + set re=1 + /\%Ufffffc23 + catch + call assert_match('E678:', v:exception) + endtry + set re& +endfunc + +func Test_large_hex_chars2() + " This used to cause a crash, the character becomes an NFA state. + try + /[\Ufffffc1f] + catch + call assert_match('E486:', v:exception) + endtry + try + set re=1 + /[\Ufffffc1f] + catch + call assert_match('E486:', v:exception) + endtry + set re& endfunc func Test_one_error_msg() diff --git a/src/testdir/test_terminal.vim b/src/testdir/test_terminal.vim index fe147227be..d1a8bd19ae 100644 --- a/src/testdir/test_terminal.vim +++ b/src/testdir/test_terminal.vim @@ -82,6 +82,21 @@ func Test_terminal_make_change() unlet g:job endfunc +func Test_terminal_paste_register() + let @" = "text to paste" + + let buf = Run_shell_in_terminal({}) + " Wait for the shell to display a prompt + call WaitForAssert({-> assert_notequal('', term_getline(buf, 1))}) + + call feedkeys("echo \\"\" \\"=37 + 5\\", 'xt') + call WaitForAssert({-> assert_match("echo text to paste 42$", getline(1))}) + call WaitForAssert({-> assert_equal('text to paste 42', getline(2))}) + + exe buf . 'bwipe!' + unlet g:job +endfunc + func Test_terminal_wipe_buffer() let buf = Run_shell_in_terminal({}) call assert_fails(buf . 'bwipe', 'E517') diff --git a/src/testdir/test_vimscript.vim b/src/testdir/test_vimscript.vim index 41a1dda7db..57e673f3ab 100644 --- a/src/testdir/test_vimscript.vim +++ b/src/testdir/test_vimscript.vim @@ -21,7 +21,7 @@ com! -nargs=1 Xout call Xout() " " Create a script that consists of the body of the function a:funcname. " Replace any ":return" by a ":finish", any argument variable by a global -" variable, and and every ":call" by a ":source" for the next following argument +" variable, and every ":call" by a ":source" for the next following argument " in the variable argument list. This function is useful if similar tests are " to be made for a ":return" from a function call or a ":finish" in a script " file. @@ -1457,6 +1457,43 @@ func Test_compound_assignment_operators() let x .= 'n' call assert_equal('2n', x) + " Test special cases: division or modulus with 0. + let x = 1 + let x /= 0 + if has('num64') + call assert_equal(0x7FFFFFFFFFFFFFFF, x) + else + call assert_equal(0x7fffffff, x) + endif + + let x = -1 + let x /= 0 + if has('num64') + call assert_equal(-0x7FFFFFFFFFFFFFFF, x) + else + call assert_equal(-0x7fffffff, x) + endif + + let x = 0 + let x /= 0 + if has('num64') + call assert_equal(-0x7FFFFFFFFFFFFFFF - 1, x) + else + call assert_equal(-0x7FFFFFFF - 1, x) + endif + + let x = 1 + let x %= 0 + call assert_equal(0, x) + + let x = -1 + let x %= 0 + call assert_equal(0, x) + + let x = 0 + let x %= 0 + call assert_equal(0, x) + " Test for string let x = 'str' let x .= 'ing' diff --git a/src/testdir/test_visual.vim b/src/testdir/test_visual.vim index 77064bab26..abf131c384 100644 --- a/src/testdir/test_visual.vim +++ b/src/testdir/test_visual.vim @@ -1,8 +1,4 @@ " Tests for various Visual mode. -if !has('visual') - finish -endif - func Test_block_shift_multibyte() " Uses double-wide character. @@ -397,3 +393,14 @@ func Test_Visual_paragraph_textobject() bwipe! endfunc + +func Test_curswant_not_changed() + new + call setline(1, ['one', 'two']) + au InsertLeave * call getcurpos() + call feedkeys("gg0\jI123 \j", 'xt') + call assert_equal([0, 2, 1, 0, 1], getcurpos()) + + bwipe! + au! InsertLeave +endfunc diff --git a/src/testdir/test_window_cmd.vim b/src/testdir/test_window_cmd.vim index 587ae23da8..5189e681fc 100644 --- a/src/testdir/test_window_cmd.vim +++ b/src/testdir/test_window_cmd.vim @@ -615,4 +615,132 @@ func Test_window_prevwin() delfunc Fun_RenewFile endfunc +func Test_relative_cursor_position_in_one_line_window() + new + only + call setline(1, range(1, 10000)) + normal 50% + let lnum = getcurpos()[1] + split + split + " make third window take as many lines as possible, other windows will + " become one line + 3wincmd w + for i in range(1, &lines - 6) + wincmd + + redraw! + endfor + + " first and second window should show cursor line + let wininfo = getwininfo() + call assert_equal(lnum, wininfo[0].topline) + call assert_equal(lnum, wininfo[1].topline) + + only! + bwipe! +endfunc + +func Test_relative_cursor_position_after_move_and_resize() + let so_save = &so + set so=0 + enew + call setline(1, range(1, 10000)) + normal 50% + split + 1wincmd w + " Move cursor to first line in window + normal H + redraw! + " Reduce window height to two lines + let height = winheight(0) + while winheight(0) > 2 + wincmd - + redraw! + endwhile + " move cursor to second/last line in window + normal j + " restore previous height + while winheight(0) < height + wincmd + + redraw! + endwhile + " make window two lines again + while winheight(0) > 2 + wincmd - + redraw! + endwhile + + " cursor should be at bottom line + let info = getwininfo(win_getid())[0] + call assert_equal(info.topline + 1, getcurpos()[1]) + + only! + bwipe! + let &so = so_save +endfunc + +func Test_relative_cursor_position_after_resize() + let so_save = &so + set so=0 + enew + call setline(1, range(1, 10000)) + normal 50% + split + 1wincmd w + let winid1 = win_getid() + let info = getwininfo(winid1)[0] + " Move cursor to second line in window + exe "normal " . (info.topline + 1) . "G" + redraw! + let lnum = getcurpos()[1] + + " Make the window only two lines high, cursor should end up in top line + 2wincmd w + exe (info.height - 2) . "wincmd +" + redraw! + let info = getwininfo(winid1)[0] + call assert_equal(lnum, info.topline) + + only! + bwipe! + let &so = so_save +endfunc + +func Test_relative_cursor_second_line_after_resize() + let so_save = &so + set so=0 + enew + call setline(1, range(1, 10000)) + normal 50% + split + 1wincmd w + let winid1 = win_getid() + let info = getwininfo(winid1)[0] + + " Make the window only two lines high + 2wincmd _ + + " Move cursor to second line in window + normal H + normal j + + " Make window size bigger, then back to 2 lines + for i in range(1, 10) + wincmd + + redraw! + endfor + for i in range(1, 10) + wincmd - + redraw! + endfor + + " cursor should end up in bottom line + let info = getwininfo(winid1)[0] + call assert_equal(info.topline + 1, getcurpos()[1]) + + only! + bwipe! + let &so = so_save +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/ui.c b/src/ui.c index 2c2f8ae543..199ce61114 100644 --- a/src/ui.c +++ b/src/ui.c @@ -1758,7 +1758,7 @@ clip_gen_set_selection(VimClipboard *cbd) if (!clip_did_set_selection) { /* Updating postponed, so that accessing the system clipboard won't - * hang Vim when accessing it many times (e.g. on a :g comand). */ + * hang Vim when accessing it many times (e.g. on a :g command). */ if ((cbd == &clip_plus && (clip_unnamed_saved & CLIP_UNNAMED_PLUS)) || (cbd == &clip_star && (clip_unnamed_saved & CLIP_UNNAMED))) { diff --git a/src/version.c b/src/version.c index 284a9f7a2d..b456115116 100644 --- a/src/version.c +++ b/src/version.c @@ -41,7 +41,7 @@ init_longVersion(void) { /* * Construct the long version string. Necessary because - * VAX C can't catenate strings in the preprocessor. + * VAX C can't concatenate strings in the preprocessor. */ strcpy(longVersion, VIM_VERSION_LONG_DATE); strcat(longVersion, __DATE__); @@ -794,6 +794,52 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 999, +/**/ + 998, +/**/ + 997, +/**/ + 996, +/**/ + 995, +/**/ + 994, +/**/ + 993, +/**/ + 992, +/**/ + 991, +/**/ + 990, +/**/ + 989, +/**/ + 988, +/**/ + 987, +/**/ + 986, +/**/ + 985, +/**/ + 984, +/**/ + 983, +/**/ + 982, +/**/ + 981, +/**/ + 980, +/**/ + 979, +/**/ + 978, +/**/ + 977, /**/ 976, /**/ diff --git a/src/winclip.c b/src/winclip.c index 2d4d97e78b..4d0a2c38c9 100644 --- a/src/winclip.c +++ b/src/winclip.c @@ -22,7 +22,6 @@ * posix environment. */ #ifdef FEAT_CYGWIN_WIN32_CLIPBOARD -# define MSWIN # define WIN32_LEAN_AND_MEAN # include # include "winclip.pro" @@ -299,9 +298,7 @@ clip_mch_request_selection(VimClipboard *cbd) VimClipType_t metadata = { -1, -1, -1, -1 }; HGLOBAL hMem = NULL; char_u *str = NULL; -#if defined(MSWIN) char_u *to_free = NULL; -#endif HGLOBAL rawh = NULL; int str_size = 0; int maxlen; @@ -361,7 +358,6 @@ clip_mch_request_selection(VimClipboard *cbd) } if (str == NULL) { -#if defined(MSWIN) /* Try to get the clipboard in Unicode if it's not an empty string. */ if (IsClipboardFormatAvailable(CF_UNICODETEXT) && metadata.ucslen != 0) { @@ -391,10 +387,8 @@ clip_mch_request_selection(VimClipboard *cbd) GlobalUnlock(hMemW); } } - else -#endif - /* Get the clipboard in the Active codepage. */ - if (IsClipboardFormatAvailable(CF_TEXT)) + /* Get the clipboard in the Active codepage. */ + else if (IsClipboardFormatAvailable(CF_TEXT)) { if ((hMem = GetClipboardData(CF_TEXT)) != NULL) { @@ -417,7 +411,6 @@ clip_mch_request_selection(VimClipboard *cbd) break; } -#if defined(MSWIN) /* The text is in the active codepage. Convert to * 'encoding', going through UTF-16. */ acp_to_enc(str, str_size, &to_free, &maxlen); @@ -426,7 +419,6 @@ clip_mch_request_selection(VimClipboard *cbd) str_size = maxlen; str = to_free; } -#endif } } } @@ -454,9 +446,7 @@ clip_mch_request_selection(VimClipboard *cbd) if (rawh != NULL) GlobalUnlock(rawh); CloseClipboard(); -#if defined(MSWIN) vim_free(to_free); -#endif } /* @@ -471,9 +461,7 @@ clip_mch_set_selection(VimClipboard *cbd) HGLOBAL hMemRaw = NULL; HGLOBAL hMem = NULL; HGLOBAL hMemVim = NULL; -# if defined(MSWIN) HGLOBAL hMemW = NULL; -# endif /* If the '*' register isn't already filled in, fill it in now */ cbd->owned = TRUE; @@ -508,7 +496,6 @@ clip_mch_set_selection(VimClipboard *cbd) metadata.rawlen = 0; } -# if defined(MSWIN) { WCHAR *out; int len = metadata.txtlen; @@ -550,7 +537,6 @@ clip_mch_set_selection(VimClipboard *cbd) metadata.ucslen = len; } } -# endif /* Allocate memory for the text, add one NUL byte to terminate the string. */ @@ -590,13 +576,11 @@ clip_mch_set_selection(VimClipboard *cbd) { SetClipboardData(cbd->format, hMemVim); hMemVim = 0; -# if defined(MSWIN) if (hMemW != NULL) { if (SetClipboardData(CF_UNICODETEXT, hMemW) != NULL) hMemW = NULL; } -# endif /* Always use CF_TEXT. On Win98 Notepad won't obtain the * CF_UNICODETEXT text, only CF_TEXT. */ SetClipboardData(CF_TEXT, hMem); @@ -611,10 +595,8 @@ clip_mch_set_selection(VimClipboard *cbd) GlobalFree(hMemRaw); if (hMem) GlobalFree(hMem); -# if defined(MSWIN) if (hMemW) GlobalFree(hMemW); -# endif if (hMemVim) GlobalFree(hMemVim); } @@ -746,7 +728,6 @@ utf16_to_enc(short_u *str, int *lenp) return enc_str; } -#if defined(MSWIN) || defined(PROTO) /* * Convert from the active codepage to 'encoding'. * Input is "str[str_size]". @@ -796,4 +777,3 @@ enc_to_acp( vim_free(widestr); } } -#endif diff --git a/src/window.c b/src/window.c index e1ed3fdcee..aa66544e24 100644 --- a/src/window.c +++ b/src/window.c @@ -5724,8 +5724,11 @@ win_drag_vsep_line(win_T *dragwin, int offset) set_fraction(win_T *wp) { if (wp->w_height > 1) + // When cursor is in the first line the percentage is computed as if + // it's halfway that line. Thus with two lines it is 25%, with three + // lines 17%, etc. Similarly for the last line: 75%, 83%, etc. wp->w_fraction = ((long)wp->w_wrow * FRACTION_MULT - + wp->w_height / 2) / (long)wp->w_height; + + FRACTION_MULT / 2) / (long)wp->w_height; } /* @@ -5775,8 +5778,8 @@ scroll_to_fraction(win_T *wp, int prev_height) int sline, line_size; int height = wp->w_height; - /* Don't change w_topline when height is zero. Don't set w_topline when - * 'scrollbind' is set and this isn't the current window. */ + // Don't change w_topline when height is zero. Don't set w_topline when + // 'scrollbind' is set and this isn't the current window. if (height > 0 && (!wp->w_p_scb || wp == curwin)) { /* @@ -5786,8 +5789,8 @@ scroll_to_fraction(win_T *wp, int prev_height) lnum = wp->w_cursor.lnum; if (lnum < 1) /* can happen when starting up */ lnum = 1; - wp->w_wrow = ((long)wp->w_fraction * (long)height - 1L - + FRACTION_MULT / 2) / FRACTION_MULT; + wp->w_wrow = ((long)wp->w_fraction * (long)height - 1L) + / FRACTION_MULT; line_size = plines_win_col(wp, lnum, (long)(wp->w_cursor.col)) - 1; sline = wp->w_wrow - line_size; @@ -5823,7 +5826,6 @@ scroll_to_fraction(win_T *wp, int prev_height) --wp->w_wrow; } } - set_topline(wp, lnum); } else if (sline > 0) { @@ -5864,13 +5866,12 @@ scroll_to_fraction(win_T *wp, int prev_height) } else if (sline > 0) { - /* First line of file reached, use that as topline. */ + // First line of file reached, use that as topline. lnum = 1; wp->w_wrow -= sline; } - - set_topline(wp, lnum); } + set_topline(wp, lnum); } if (wp == curwin) diff --git a/src/xxd/xxd.c b/src/xxd/xxd.c index c24089e4ed..b9f6041ba0 100644 --- a/src/xxd/xxd.c +++ b/src/xxd/xxd.c @@ -71,7 +71,7 @@ # define _CRT_SECURE_NO_DEPRECATE # define _CRT_NONSTDC_NO_DEPRECATE #endif -#if !defined(CYGWIN) && (defined(CYGWIN32) || defined(__CYGWIN__) || defined(__CYGWIN32__)) +#if !defined(CYGWIN) && defined(__CYGWIN__) # define CYGWIN #endif