diff --git a/runtime/autoload/dist/ft.vim b/runtime/autoload/dist/ft.vim index a36f615d61..fd14062356 100644 --- a/runtime/autoload/dist/ft.vim +++ b/runtime/autoload/dist/ft.vim @@ -896,6 +896,23 @@ export def FTtf() setf tf enddef +# Determine if a *.src file is Kuka Robot Language +export def FTsrc() + if exists("g:filetype_src") + exe "setf " .. g:filetype_src + elseif getline(nextnonblank(1)) =~? '^\s*\%(&\w\+\|\%(global\s\+\)\?def\>\)' + setf krl + endif +enddef + +# Determine if a *.dat file is Kuka Robot Language +export def FTdat() + if exists("g:filetype_dat") + exe "setf " .. g:filetype_dat + elseif getline(nextnonblank(1)) =~? '^\s*\%(&\w\+\|defdat\>\)' + setf krl + endif +enddef # Uncomment this line to check for compilation errors early # defcompile diff --git a/runtime/doc/indent.txt b/runtime/doc/indent.txt index 6e8f35b2d2..69a03f977d 100644 --- a/runtime/doc/indent.txt +++ b/runtime/doc/indent.txt @@ -42,11 +42,12 @@ is not a C compiler: it does not recognize all syntax. One requirement is that toplevel functions have a '{' in the first column. Otherwise they are easily confused with declarations. -These four options control C program indenting: +These five options control C program indenting: 'cindent' Enables Vim to perform C program indenting automatically. 'cinkeys' Specifies which keys trigger reindenting in insert mode. 'cinoptions' Sets your preferred indent style. 'cinwords' Defines keywords that start an extra indent in the next line. +'cinscopedecls' Defines strings that are recognized as a C++ scope declaration. If 'lisp' is not on and 'equalprg' is empty, the "=" operator indents using Vim's built-in algorithm rather than calling an external program. @@ -293,8 +294,9 @@ The examples below assume a 'shiftwidth' of 4. < *cino-g* gN Place C++ scope declarations N characters from the indent of the - block they are in. (default 'shiftwidth'). A scope declaration - can be "public:", "protected:" or "private:". + block they are in. (default 'shiftwidth'). By default, a scope + declaration is "public:", "protected:" or "private:". This can + be adjusted with the 'cinscopedecls' option. cino= cino=g0 > { { diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index 801d8f0332..0f134e686d 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -1666,13 +1666,23 @@ A jump table for the options with a short description can be found at |Q_op|. matter, include the keyword both the uppercase and lowercase: "if,If,IF". - *'clipboard'* *'cb'* + *'cinscopedecls'* *'cinsd'* +'cinscopedecls' 'cinsd' string (default "public,protected,private") + local to buffer + {not available when compiled without the |+cindent| + feature} + Keywords that are interpreted as a C++ scope declaration by |cino-g|. + Useful e.g. for working with the Qt framework that defines additional + scope declarations "signals", "public slots" and "private slots": > + set cinscopedecls+=signals,public\ slots,private\ slots + +< *'clipboard'* *'cb'* 'clipboard' 'cb' string (default "autoselect,exclude:cons\|linux" for X-windows, "" otherwise) global {only in GUI versions or when the |+xterm_clipboard| feature is included} - This option is a list of comma separated names. + This option is a list of comma-separated names. Note: if one of the items is "exclude:", then you can't add an item after that. Therefore do append an item with += but use ^= to prepend, e.g.: > diff --git a/runtime/doc/quickref.txt b/runtime/doc/quickref.txt index e2f173a8cc..d90fd4b70c 100644 --- a/runtime/doc/quickref.txt +++ b/runtime/doc/quickref.txt @@ -644,6 +644,7 @@ Short explanation of each option: *option-list* 'cinkeys' 'cink' keys that trigger indent when 'cindent' is set 'cinoptions' 'cino' how to do indenting when 'cindent' is set 'cinwords' 'cinw' words where 'si' and 'cin' add an indent +'cinscopedecls' 'cinsd' words that are recognized by 'cino-g' 'clipboard' 'cb' use the clipboard as the unnamed register 'cmdheight' 'ch' number of lines to use for the command-line 'cmdwinheight' 'cwh' height of the command-line window diff --git a/runtime/filetype.vim b/runtime/filetype.vim index 7aeed626a9..4aa5743dae 100644 --- a/runtime/filetype.vim +++ b/runtime/filetype.vim @@ -951,6 +951,11 @@ au BufNewFile,BufRead *.jl setf julia " Kixtart au BufNewFile,BufRead *.kix setf kix +" Kuka Robot Language +au BufNewFile,BufRead *.src\c call dist#ft#FTsrc() +au BufNewFile,BufRead *.dat\c call dist#ft#FTdat() +au BufNewFile,BufRead *.sub\c setf krl + " Kimwitu[++] au BufNewFile,BufRead *.k setf kwt @@ -1347,9 +1352,10 @@ au BufNewFile,BufRead *.pm au BufNewFile,BufRead *.pod setf pod " Php, php3, php4, etc. -" Also Phtml (was used for PHP 2 in the past) -" Also .ctp for Cake template file -au BufNewFile,BufRead *.php,*.php\d,*.phtml,*.ctp setf php +" Also Phtml (was used for PHP 2 in the past). +" Also .ctp for Cake template file. +" Also .phpt for php tests. +au BufNewFile,BufRead *.php,*.php\d,*.phtml,*.ctp,*.phpt setf php " PHP config au BufNewFile,BufRead php.ini-* setf dosini diff --git a/runtime/optwin.vim b/runtime/optwin.vim index a44901d971..d032a4b2bd 100644 --- a/runtime/optwin.vim +++ b/runtime/optwin.vim @@ -624,6 +624,8 @@ call BinOptionG("scf", &scf) if has("gui") call AddOption("mousehide", gettext("hide the mouse pointer while typing")) call BinOptionG("mh", &mh) + call AddOption("mousemoveevent", gettext("report mouse movement events")) + call BinOptionG("mousemev", &mousemev) endif call AddOption("mousemodel", gettext("\"extend\", \"popup\" or \"popup_setpos\"; what the right\nmouse button is used for")) call OptionG("mousem", &mousem) @@ -946,6 +948,9 @@ if has("cindent") call AddOption("cinwords", gettext("list of words that cause more C-indent")) call append("$", "\t" .. s:local_to_buffer) call OptionL("cinw") + call AddOption("cinscopedecls", gettext("list of scope declaration names used by cino-g")) + call append("$", "\t" .. s:local_to_buffer) + call OptionL("cinsd") call AddOption("indentexpr", gettext("expression used to obtain the indent of a line")) call append("$", "\t" .. s:local_to_buffer) call OptionL("inde") diff --git a/src/buffer.c b/src/buffer.c index d7f66638a0..a17ffb2903 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -2357,6 +2357,7 @@ free_buf_options( #ifdef FEAT_CINDENT clear_string_option(&buf->b_p_cink); clear_string_option(&buf->b_p_cino); + clear_string_option(&buf->b_p_cinsd); #endif #if defined(FEAT_CINDENT) || defined(FEAT_SMARTINDENT) clear_string_option(&buf->b_p_cinw); diff --git a/src/change.c b/src/change.c index a5820fcbe4..8dfaebcaad 100644 --- a/src/change.c +++ b/src/change.c @@ -640,9 +640,13 @@ changed_common( if (hasAnyFolding(wp)) set_topline(wp, wp->w_topline); #endif - // Relative numbering may require updating more. + // If lines have been added or removed, relative numbering always + // requires a redraw. if (wp->w_p_rnu && xtra != 0) - redraw_win_later(wp, SOME_VALID); + { + wp->w_last_cursor_lnum_rnu = 0; + redraw_win_later(wp, VALID); + } #ifdef FEAT_SYN_HL // Cursor line highlighting probably need to be updated with // "VALID" if it's below the change. diff --git a/src/cindent.c b/src/cindent.c index ca21c123e0..268d274aec 100644 --- a/src/cindent.c +++ b/src/cindent.c @@ -423,20 +423,37 @@ cin_islabel_skip(char_u **s) * Recognize a "public/private/protected" scope declaration label. */ static int -cin_isscopedecl(char_u *s) +cin_isscopedecl(char_u *p) { - int i; + size_t cinsd_len; + char_u *cinsd_buf; + char_u *cinsd; + size_t len; + char_u *skip; + char_u *s = cin_skipcomment(p); + int found = FALSE; - s = cin_skipcomment(s); - if (STRNCMP(s, "public", 6) == 0) - i = 6; - else if (STRNCMP(s, "protected", 9) == 0) - i = 9; - else if (STRNCMP(s, "private", 7) == 0) - i = 7; - else + cinsd_len = STRLEN(curbuf->b_p_cinsd) + 1; + cinsd_buf = alloc(cinsd_len); + if (cinsd_buf == NULL) return FALSE; - return (*(s = cin_skipcomment(s + i)) == ':' && s[1] != ':'); + + for (cinsd = curbuf->b_p_cinsd; *cinsd; ) + { + len = copy_option_part(&cinsd, cinsd_buf, cinsd_len, ","); + if (STRNCMP(s, cinsd_buf, len) == 0) + { + skip = cin_skipcomment(s + len); + if (*skip == ':' && skip[1] != ':') + { + found = TRUE; + break; + } + } + } + + vim_free(cinsd_buf); + return found; } /* diff --git a/src/edit.c b/src/edit.c index 61f753524a..ac9bcb5396 100644 --- a/src/edit.c +++ b/src/edit.c @@ -293,14 +293,9 @@ edit( conceal_check_cursor_line(cursor_line_was_concealed); #endif - // Need to recompute the cursor position, it might move when the cursor - // is on a TAB or special character. - // ptr2cells() treats a TAB character as double-width. - if (ptr2cells(ml_get_cursor()) > 1) - { - curwin->w_valid &= ~VALID_VIRTCOL; - curs_columns(TRUE); - } + // need to position cursor again when on a TAB + if (gchar_cursor() == TAB) + curwin->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL); /* * Enable langmap or IME, indicated by 'iminsert'. @@ -1307,6 +1302,9 @@ docomplete: disable_fold_update--; #endif compl_busy = FALSE; +#ifdef FEAT_SMARTINDENT + can_si = TRUE; // allow smartindenting +#endif break; case Ctrl_Y: // copy from previous line or scroll down @@ -3158,21 +3156,20 @@ mb_replace_pop_ins(int cc) replace_push(c); break; } + + buf[0] = c; + for (i = 1; i < n; ++i) + buf[i] = replace_pop(); + if (utf_iscomposing(utf_ptr2char(buf))) + ins_bytes_len(buf, n); else { - buf[0] = c; - for (i = 1; i < n; ++i) - buf[i] = replace_pop(); - if (utf_iscomposing(utf_ptr2char(buf))) - ins_bytes_len(buf, n); - else - { - // Not a composing char, put it back. - for (i = n - 1; i >= 0; --i) - replace_push(buf[i]); - break; - } + // Not a composing char, put it back. + for (i = n - 1; i >= 0; --i) + replace_push(buf[i]); + break; } + } } @@ -3711,8 +3708,9 @@ ins_esc( State = NORMAL; trigger_modechanged(); - // need to position cursor again (e.g. when on a TAB ) - changed_cline_bef_curs(); + // need to position cursor again when on a TAB + if (gchar_cursor() == TAB) + curwin->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL); setmouse(); #ifdef CURSOR_SHAPE diff --git a/src/ex_docmd.c b/src/ex_docmd.c index 1c1733a6cd..ccd69a46cd 100644 --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -1739,6 +1739,7 @@ do_one_cmd( exarg_T ea; // Ex command arguments cmdmod_T save_cmdmod; int save_reg_executing = reg_executing; + int save_pending_end_reg_executing = pending_end_reg_executing; int ni; // set when Not Implemented char_u *cmd; int starts_with_colon = FALSE; @@ -2636,6 +2637,7 @@ doend: undo_cmdmod(&cmdmod); cmdmod = save_cmdmod; reg_executing = save_reg_executing; + pending_end_reg_executing = save_pending_end_reg_executing; if (ea.nextcmd && *ea.nextcmd == NUL) // not really a next command ea.nextcmd = NULL; @@ -8296,6 +8298,9 @@ ex_redraw(exarg_T *eap) RedrawingDisabled = r; p_lz = p; + // After drawing the statusline screen_attr may still be set. + screen_stop_highlight(); + // Reset msg_didout, so that a message that's there is overwritten. msg_didout = FALSE; msg_col = 0; @@ -8472,6 +8477,7 @@ save_current_state(save_state_T *sst) sst->save_finish_op = finish_op; sst->save_opcount = opcount; sst->save_reg_executing = reg_executing; + sst->save_pending_end_reg_executing = pending_end_reg_executing; msg_scroll = FALSE; // no msg scrolling in Normal mode restart_edit = 0; // don't go to Insert mode @@ -8501,6 +8507,7 @@ restore_current_state(save_state_T *sst) finish_op = sst->save_finish_op; opcount = sst->save_opcount; reg_executing = sst->save_reg_executing; + pending_end_reg_executing = sst->save_pending_end_reg_executing; msg_didout |= sst->save_msg_didout; // don't reset msg_didout now current_sctx.sc_version = sst->save_script_version; diff --git a/src/fileio.c b/src/fileio.c index dbe4bf4c0c..f47daa14cf 100644 --- a/src/fileio.c +++ b/src/fileio.c @@ -1245,30 +1245,29 @@ retry: read_buf_col += n; break; } - else + + // Append whole line and new-line. Change NL + // to NUL to reverse the effect done below. + for (ni = 0; ni < n; ++ni) { - // Append whole line and new-line. Change NL - // to NUL to reverse the effect done below. - for (ni = 0; ni < n; ++ni) - { - if (p[ni] == NL) - ptr[tlen++] = NUL; - else - ptr[tlen++] = p[ni]; - } - ptr[tlen++] = NL; - read_buf_col = 0; - if (++read_buf_lnum > from) - { - // When the last line didn't have an - // end-of-line don't add it now either. - if (!curbuf->b_p_eol) - --tlen; - size = tlen; - eof = TRUE; - break; - } + if (p[ni] == NL) + ptr[tlen++] = NUL; + else + ptr[tlen++] = p[ni]; } + ptr[tlen++] = NL; + read_buf_col = 0; + if (++read_buf_lnum > from) + { + // When the last line didn't have an + // end-of-line don't add it now either. + if (!curbuf->b_p_eol) + --tlen; + size = tlen; + eof = TRUE; + break; + } + } } } diff --git a/src/getchar.c b/src/getchar.c index 3652daed0f..d0549d3508 100644 --- a/src/getchar.c +++ b/src/getchar.c @@ -1421,7 +1421,7 @@ static int old_mouse_row; // mouse_row related to old_char static int old_mouse_col; // mouse_col related to old_char static int old_KeyStuffed; // whether old_char was stuffed -static int can_get_old_char() +static int can_get_old_char(void) { // If the old character was not stuffed and characters have been added to // the stuff buffer, need to first get the stuffed characters instead. @@ -2963,7 +2963,7 @@ handle_mapping( /* * unget one character (can only be done once!) - * If the character was stuffed, vgetc() will get it next time it was called. + * If the character was stuffed, vgetc() will get it next time it is called. * Otherwise vgetc() will only get it when the stuff buffer is empty. */ void @@ -2976,6 +2976,27 @@ vungetc(int c) old_KeyStuffed = KeyStuffed; } +/* + * When peeking and not getting a character, reg_executing cannot be cleared + * yet, so set a flag to clear it later. + */ + static void +check_end_reg_executing(int advance) +{ + if (reg_executing != 0 && (typebuf.tb_maplen == 0 + || pending_end_reg_executing)) + { + if (advance) + { + reg_executing = 0; + pending_end_reg_executing = FALSE; + } + else + pending_end_reg_executing = TRUE; + } + +} + /* * Get a byte: * 1. from the stuffbuffer @@ -3039,8 +3060,7 @@ vgetorpeek(int advance) init_typebuf(); start_stuff(); - if (advance && typebuf.tb_maplen == 0) - reg_executing = 0; + check_end_reg_executing(advance); do { /* @@ -3081,6 +3101,7 @@ vgetorpeek(int advance) #ifdef FEAT_CMDL_INFO int showcmd_idx; #endif + check_end_reg_executing(advance); /* * ui_breakcheck() is slow, don't use it too often when * inside a mapping. But call it each time for typed diff --git a/src/globals.h b/src/globals.h index 28e636a63e..171d2b1c0f 100644 --- a/src/globals.h +++ b/src/globals.h @@ -1125,6 +1125,8 @@ EXTERN int ex_no_reprint INIT(= FALSE); // no need to print after z or p EXTERN int reg_recording INIT(= 0); // register for recording or zero EXTERN int reg_executing INIT(= 0); // register being executed or zero +// Flag set when peeking a character and found the end of executed register +EXTERN int pending_end_reg_executing INIT(= 0); // Set when a modifyOtherKeys sequence was seen, then simplified mappings will // no longer be used. diff --git a/src/memline.c b/src/memline.c index abd2360ae8..f38e029bd1 100644 --- a/src/memline.c +++ b/src/memline.c @@ -3165,94 +3165,93 @@ ml_append_int( */ break; } - else // pointer block full + // pointer block full + /* + * split the pointer block + * allocate a new pointer block + * move some of the pointer into the new block + * prepare for updating the parent block + */ + for (;;) // do this twice when splitting block 1 { - /* - * split the pointer block - * allocate a new pointer block - * move some of the pointer into the new block - * prepare for updating the parent block - */ - for (;;) // do this twice when splitting block 1 - { - hp_new = ml_new_ptr(mfp); - if (hp_new == NULL) // TODO: try to fix tree - goto theend; - pp_new = (PTR_BL *)(hp_new->bh_data); + hp_new = ml_new_ptr(mfp); + if (hp_new == NULL) // TODO: try to fix tree + goto theend; + pp_new = (PTR_BL *)(hp_new->bh_data); - if (hp->bh_bnum != 1) - break; + if (hp->bh_bnum != 1) + break; - /* - * if block 1 becomes full the tree is given an extra level - * The pointers from block 1 are moved into the new block. - * block 1 is updated to point to the new block - * then continue to split the new block - */ - mch_memmove(pp_new, pp, (size_t)page_size); - pp->pb_count = 1; - pp->pb_pointer[0].pe_bnum = hp_new->bh_bnum; - pp->pb_pointer[0].pe_line_count = buf->b_ml.ml_line_count; - pp->pb_pointer[0].pe_old_lnum = 1; - pp->pb_pointer[0].pe_page_count = 1; - mf_put(mfp, hp, TRUE, FALSE); // release block 1 - hp = hp_new; // new block is to be split - pp = pp_new; - CHECK(stack_idx != 0, _("stack_idx should be 0")); - ip->ip_index = 0; - ++stack_idx; // do block 1 again later - } /* - * move the pointers after the current one to the new block - * If there are none, the new entry will be in the new block. + * if block 1 becomes full the tree is given an extra level + * The pointers from block 1 are moved into the new block. + * block 1 is updated to point to the new block + * then continue to split the new block */ - total_moved = pp->pb_count - pb_idx - 1; - if (total_moved) - { - mch_memmove(&pp_new->pb_pointer[0], + mch_memmove(pp_new, pp, (size_t)page_size); + pp->pb_count = 1; + pp->pb_pointer[0].pe_bnum = hp_new->bh_bnum; + pp->pb_pointer[0].pe_line_count = buf->b_ml.ml_line_count; + pp->pb_pointer[0].pe_old_lnum = 1; + pp->pb_pointer[0].pe_page_count = 1; + mf_put(mfp, hp, TRUE, FALSE); // release block 1 + hp = hp_new; // new block is to be split + pp = pp_new; + CHECK(stack_idx != 0, _("stack_idx should be 0")); + ip->ip_index = 0; + ++stack_idx; // do block 1 again later + } + /* + * move the pointers after the current one to the new block + * If there are none, the new entry will be in the new block. + */ + total_moved = pp->pb_count - pb_idx - 1; + if (total_moved) + { + mch_memmove(&pp_new->pb_pointer[0], &pp->pb_pointer[pb_idx + 1], (size_t)(total_moved) * sizeof(PTR_EN)); - pp_new->pb_count = total_moved; - pp->pb_count -= total_moved - 1; - pp->pb_pointer[pb_idx + 1].pe_bnum = bnum_right; - pp->pb_pointer[pb_idx + 1].pe_line_count = line_count_right; - pp->pb_pointer[pb_idx + 1].pe_page_count = page_count_right; - if (lnum_right) - pp->pb_pointer[pb_idx + 1].pe_old_lnum = lnum_right; - } - else - { - pp_new->pb_count = 1; - pp_new->pb_pointer[0].pe_bnum = bnum_right; - pp_new->pb_pointer[0].pe_line_count = line_count_right; - pp_new->pb_pointer[0].pe_page_count = page_count_right; - pp_new->pb_pointer[0].pe_old_lnum = lnum_right; - } - pp->pb_pointer[pb_idx].pe_bnum = bnum_left; - pp->pb_pointer[pb_idx].pe_line_count = line_count_left; - pp->pb_pointer[pb_idx].pe_page_count = page_count_left; - if (lnum_left) - pp->pb_pointer[pb_idx].pe_old_lnum = lnum_left; - lnum_left = 0; - lnum_right = 0; - - /* - * recompute line counts - */ - line_count_right = 0; - for (i = 0; i < (int)pp_new->pb_count; ++i) - line_count_right += pp_new->pb_pointer[i].pe_line_count; - line_count_left = 0; - for (i = 0; i < (int)pp->pb_count; ++i) - line_count_left += pp->pb_pointer[i].pe_line_count; - - bnum_left = hp->bh_bnum; - bnum_right = hp_new->bh_bnum; - page_count_left = 1; - page_count_right = 1; - mf_put(mfp, hp, TRUE, FALSE); - mf_put(mfp, hp_new, TRUE, FALSE); + pp_new->pb_count = total_moved; + pp->pb_count -= total_moved - 1; + pp->pb_pointer[pb_idx + 1].pe_bnum = bnum_right; + pp->pb_pointer[pb_idx + 1].pe_line_count = line_count_right; + pp->pb_pointer[pb_idx + 1].pe_page_count = page_count_right; + if (lnum_right) + pp->pb_pointer[pb_idx + 1].pe_old_lnum = lnum_right; } + else + { + pp_new->pb_count = 1; + pp_new->pb_pointer[0].pe_bnum = bnum_right; + pp_new->pb_pointer[0].pe_line_count = line_count_right; + pp_new->pb_pointer[0].pe_page_count = page_count_right; + pp_new->pb_pointer[0].pe_old_lnum = lnum_right; + } + pp->pb_pointer[pb_idx].pe_bnum = bnum_left; + pp->pb_pointer[pb_idx].pe_line_count = line_count_left; + pp->pb_pointer[pb_idx].pe_page_count = page_count_left; + if (lnum_left) + pp->pb_pointer[pb_idx].pe_old_lnum = lnum_left; + lnum_left = 0; + lnum_right = 0; + + /* + * recompute line counts + */ + line_count_right = 0; + for (i = 0; i < (int)pp_new->pb_count; ++i) + line_count_right += pp_new->pb_pointer[i].pe_line_count; + line_count_left = 0; + for (i = 0; i < (int)pp->pb_count; ++i) + line_count_left += pp->pb_pointer[i].pe_line_count; + + bnum_left = hp->bh_bnum; + bnum_right = hp_new->bh_bnum; + page_count_left = 1; + page_count_right = 1; + mf_put(mfp, hp, TRUE, FALSE); + mf_put(mfp, hp_new, TRUE, FALSE); + } /* diff --git a/src/option.c b/src/option.c index 66421ac9e6..cb2f26d52f 100644 --- a/src/option.c +++ b/src/option.c @@ -4492,38 +4492,36 @@ set_option_value( #endif if (flags & P_STRING) return set_string_option(opt_idx, string, opt_flags); - else + + varp = get_varp_scope(&(options[opt_idx]), opt_flags); + if (varp != NULL) // hidden option is not changed { - varp = get_varp_scope(&(options[opt_idx]), opt_flags); - if (varp != NULL) // hidden option is not changed + if (number == 0 && string != NULL) { - if (number == 0 && string != NULL) + int idx; + + // Either we are given a string or we are setting option + // to zero. + for (idx = 0; string[idx] == '0'; ++idx) + ; + if (string[idx] != NUL || idx == 0) { - int idx; + // There's another character after zeros or the string + // is empty. In both cases, we are trying to set a + // num option using a string. + semsg(_(e_number_required_after_str_equal_str), + name, string); + return NULL; // do nothing as we hit an error - // Either we are given a string or we are setting option - // to zero. - for (idx = 0; string[idx] == '0'; ++idx) - ; - if (string[idx] != NUL || idx == 0) - { - // There's another character after zeros or the string - // is empty. In both cases, we are trying to set a - // num option using a string. - semsg(_(e_number_required_after_str_equal_str), - name, string); - return NULL; // do nothing as we hit an error - - } } - if (flags & P_NUM) - return set_num_option(opt_idx, varp, number, - NULL, 0, opt_flags); - else - return set_bool_option(opt_idx, varp, (int)number, - opt_flags); } + if (flags & P_NUM) + return set_num_option(opt_idx, varp, number, + NULL, 0, opt_flags); + else + return set_bool_option(opt_idx, varp, (int)number, opt_flags); } + } return NULL; } @@ -5557,6 +5555,7 @@ get_varp(struct vimoption *p) case PV_CIN: return (char_u *)&(curbuf->b_p_cin); case PV_CINK: return (char_u *)&(curbuf->b_p_cink); case PV_CINO: return (char_u *)&(curbuf->b_p_cino); + case PV_CINSD: return (char_u *)&(curbuf->b_p_cinsd); #endif #if defined(FEAT_SMARTINDENT) || defined(FEAT_CINDENT) case PV_CINW: return (char_u *)&(curbuf->b_p_cinw); @@ -6131,6 +6130,8 @@ buf_copy_options(buf_T *buf, int flags) COPY_OPT_SCTX(buf, BV_CINK); buf->b_p_cino = vim_strsave(p_cino); COPY_OPT_SCTX(buf, BV_CINO); + buf->b_p_cinsd = vim_strsave(p_cinsd); + COPY_OPT_SCTX(buf, BV_CINSD); #endif // Don't copy 'filetype', it must be detected buf->b_p_ft = empty_option; diff --git a/src/option.h b/src/option.h index da85d05fd6..70596403a4 100644 --- a/src/option.h +++ b/src/option.h @@ -400,6 +400,7 @@ EXTERN int p_bl; // 'buflisted' #ifdef FEAT_CINDENT EXTERN int p_cin; // 'cindent' EXTERN char_u *p_cink; // 'cinkeys' +EXTERN char_u *p_cinsd; // 'cinscopedecls' #endif #if defined(FEAT_SMARTINDENT) || defined(FEAT_CINDENT) EXTERN char_u *p_cinw; // 'cinwords' @@ -1152,6 +1153,7 @@ enum , BV_CIN , BV_CINK , BV_CINO + , BV_CINSD #endif #if defined(FEAT_SMARTINDENT) || defined(FEAT_CINDENT) , BV_CINW diff --git a/src/optiondefs.h b/src/optiondefs.h index 645a5895a3..352bdcb7ba 100644 --- a/src/optiondefs.h +++ b/src/optiondefs.h @@ -44,6 +44,7 @@ # define PV_CIN OPT_BUF(BV_CIN) # define PV_CINK OPT_BUF(BV_CINK) # define PV_CINO OPT_BUF(BV_CINO) +# define PV_CINSD OPT_BUF(BV_CINSD) #endif #if defined(FEAT_SMARTINDENT) || defined(FEAT_CINDENT) # define PV_CINW OPT_BUF(BV_CINW) @@ -651,6 +652,15 @@ static struct vimoption options[] = (char_u *)NULL, PV_NONE, #endif {(char_u *)"", (char_u *)0L} SCTX_INIT}, + {"cinscopedecls", "cinsd", P_STRING|P_ALLOCED|P_VI_DEF|P_ONECOMMA|P_NODUP, +#ifdef FEAT_CINDENT + (char_u *)&p_cinsd, PV_CINSD, + {(char_u *)"public,protected,private", (char_u *)0L} +#else + (char_u *)NULL, PV_NONE, + {(char_u *)0L, (char_u *)0L} +#endif + SCTX_INIT}, {"cinwords", "cinw", P_STRING|P_ALLOCED|P_VI_DEF|P_ONECOMMA|P_NODUP, #if defined(FEAT_SMARTINDENT) || defined(FEAT_CINDENT) (char_u *)&p_cinw, PV_CINW, diff --git a/src/optionstr.c b/src/optionstr.c index 8de9bad6c5..6688eb51b5 100644 --- a/src/optionstr.c +++ b/src/optionstr.c @@ -260,6 +260,7 @@ check_buf_options(buf_T *buf) #ifdef FEAT_CINDENT check_string_option(&buf->b_p_cink); check_string_option(&buf->b_p_cino); + check_string_option(&buf->b_p_cinsd); parse_cino(buf); #endif check_string_option(&buf->b_p_ft); diff --git a/src/structs.h b/src/structs.h index 94a7594393..574e538301 100644 --- a/src/structs.h +++ b/src/structs.h @@ -2884,6 +2884,7 @@ struct file_buffer int b_p_cin; // 'cindent' char_u *b_p_cino; // 'cinoptions' char_u *b_p_cink; // 'cinkeys' + char_u *b_p_cinsd; // 'cinscopedecls' #endif #if defined(FEAT_CINDENT) || defined(FEAT_SMARTINDENT) char_u *b_p_cinw; // 'cinwords' @@ -4320,6 +4321,7 @@ typedef struct { int save_finish_op; int save_opcount; int save_reg_executing; + int save_pending_end_reg_executing; int save_script_version; tasave_T tabuf; } save_state_T; diff --git a/src/syntax.c b/src/syntax.c index 74687cb4d9..086d9d755e 100644 --- a/src/syntax.c +++ b/src/syntax.c @@ -2504,55 +2504,53 @@ check_state_ends(void) next_match_col = MAXCOL; break; } - else + + // handle next_list, unless at end of line and no "skipnl" or + // "skipempty" + current_next_list = cur_si->si_next_list; + current_next_flags = cur_si->si_flags; + if (!(current_next_flags & (HL_SKIPNL | HL_SKIPEMPTY)) + && syn_getcurline()[current_col] == NUL) + current_next_list = NULL; + + // When the ended item has "extend", another item with + // "keepend" now needs to check for its end. + had_extend = (cur_si->si_flags & HL_EXTEND); + + pop_current_state(); + + if (current_state.ga_len == 0) + break; + + if (had_extend && keepend_level >= 0) { - // handle next_list, unless at end of line and no "skipnl" or - // "skipempty" - current_next_list = cur_si->si_next_list; - current_next_flags = cur_si->si_flags; - if (!(current_next_flags & (HL_SKIPNL | HL_SKIPEMPTY)) - && syn_getcurline()[current_col] == NUL) - current_next_list = NULL; - - // When the ended item has "extend", another item with - // "keepend" now needs to check for its end. - had_extend = (cur_si->si_flags & HL_EXTEND); - - pop_current_state(); - + syn_update_ends(FALSE); if (current_state.ga_len == 0) break; + } - if (had_extend && keepend_level >= 0) - { - syn_update_ends(FALSE); - if (current_state.ga_len == 0) - break; - } + cur_si = &CUR_STATE(current_state.ga_len - 1); - cur_si = &CUR_STATE(current_state.ga_len - 1); - - /* - * Only for a region the search for the end continues after - * the end of the contained item. If the contained match - * included the end-of-line, break here, the region continues. - * Don't do this when: - * - "keepend" is used for the contained item - * - not at the end of the line (could be end="x$"me=e-1). - * - "excludenl" is used (HL_HAS_EOL won't be set) - */ - if (cur_si->si_idx >= 0 - && SYN_ITEMS(syn_block)[cur_si->si_idx].sp_type - == SPTYPE_START - && !(cur_si->si_flags & (HL_MATCH | HL_KEEPEND))) - { - update_si_end(cur_si, (int)current_col, TRUE); - check_keepend(); - if ((current_next_flags & HL_HAS_EOL) - && keepend_level < 0 - && syn_getcurline()[current_col] == NUL) - break; - } + /* + * Only for a region the search for the end continues after + * the end of the contained item. If the contained match + * included the end-of-line, break here, the region continues. + * Don't do this when: + * - "keepend" is used for the contained item + * - not at the end of the line (could be end="x$"me=e-1). + * - "excludenl" is used (HL_HAS_EOL won't be set) + */ + if (cur_si->si_idx >= 0 + && SYN_ITEMS(syn_block)[cur_si->si_idx].sp_type + == SPTYPE_START + && !(cur_si->si_flags & (HL_MATCH | HL_KEEPEND))) + { + update_si_end(cur_si, (int)current_col, TRUE); + check_keepend(); + if ((current_next_flags & HL_HAS_EOL) + && keepend_level < 0 + && syn_getcurline()[current_col] == NUL) + break; } } else diff --git a/src/testdir/dumps/Test_cursorcolumn_insert_on_tab_3.dump b/src/testdir/dumps/Test_cursorcolumn_insert_on_tab_3.dump new file mode 100644 index 0000000000..9d0cbed968 --- /dev/null +++ b/src/testdir/dumps/Test_cursorcolumn_insert_on_tab_3.dump @@ -0,0 +1,8 @@ +|1+0&#ffffff0|2|3|4|5|6|7|8+0&#e0e0e08|9+0&#ffffff0| @65 +|a| @5> |b| @65 +|~+0#4040ff13&| @73 +|~| @73 +|~| @73 +|~| @73 +|~| @73 +|-+2#0000000&@1| |(|i|n|s|e|r|t|)| |-@1| +0&&@42|2|,|2|-|8| @8|A|l@1| diff --git a/src/testdir/test_autocmd.vim b/src/testdir/test_autocmd.vim index b8dcfe0663..ed6be22595 100644 --- a/src/testdir/test_autocmd.vim +++ b/src/testdir/test_autocmd.vim @@ -348,6 +348,40 @@ func Test_WinClosed() unlet g:triggered endfunc +func Test_WinClosed_throws() + vnew + let bnr = bufnr() + call assert_equal(1, bufloaded(bnr)) + augroup test-WinClosed + autocmd WinClosed * throw 'foo' + augroup END + try + close + catch /.*/ + endtry + call assert_equal(0, bufloaded(bnr)) + + autocmd! test-WinClosed + augroup! test-WinClosed +endfunc + +func Test_WinClosed_throws_with_tabs() + tabnew + let bnr = bufnr() + call assert_equal(1, bufloaded(bnr)) + augroup test-WinClosed + autocmd WinClosed * throw 'foo' + augroup END + try + close + catch /.*/ + endtry + call assert_equal(0, bufloaded(bnr)) + + autocmd! test-WinClosed + augroup! test-WinClosed +endfunc + func s:AddAnAutocmd() augroup vimBarTest au BufReadCmd * echo 'hello' diff --git a/src/testdir/test_cindent.vim b/src/testdir/test_cindent.vim index d8ea4e772e..dbd4aa006e 100644 --- a/src/testdir/test_cindent.vim +++ b/src/testdir/test_cindent.vim @@ -5319,6 +5319,49 @@ func Test_cindent_change_multline() close! endfunc +func Test_cindent_scopedecls() + new + setl cindent ts=4 sw=4 + setl cino=g0 + setl cinsd+=public\ slots,signals + + let code =<< trim [CODE] + class Foo + { + public: + virtual void foo() = 0; + public slots: + void onBar(); + signals: + void baz(); + private: + int x; + }; + [CODE] + + call append(0, code) + normal gg + normal ]]=][ + + let expected =<< trim [CODE] + class Foo + { + public: + virtual void foo() = 0; + public slots: + void onBar(); + signals: + void baz(); + private: + int x; + }; + + [CODE] + + call assert_equal(expected, getline(1, '$')) + enew! | close +endfunc + func Test_cindent_pragma() new setl cindent ts=4 sw=4 diff --git a/src/testdir/test_filetype.vim b/src/testdir/test_filetype.vim index 4f0dbd7d6f..c8c159c44e 100644 --- a/src/testdir/test_filetype.vim +++ b/src/testdir/test_filetype.vim @@ -290,6 +290,7 @@ let s:filename_checks = { \ 'kivy': ['file.kv'], \ 'kix': ['file.kix'], \ 'kotlin': ['file.kt', 'file.ktm', 'file.kts'], + \ 'krl': ['file.sub', 'file.Sub', 'file.SUB'], \ 'kscript': ['file.ks'], \ 'kwt': ['file.k'], \ 'lace': ['file.ace', 'file.ACE'], @@ -395,7 +396,7 @@ let s:filename_checks = { \ 'perl': ['file.plx', 'file.al', 'file.psgi', 'gitolite.rc', '.gitolite.rc', 'example.gitolite.rc'], \ 'pf': ['pf.conf'], \ 'pfmain': ['main.cf'], - \ 'php': ['file.php', 'file.php9', 'file.phtml', 'file.ctp'], + \ 'php': ['file.php', 'file.php9', 'file.phtml', 'file.ctp', 'file.phpt'], \ 'lpc': ['file.lpc', 'file.ulpc'], \ 'pike': ['file.pike', 'file.pmod'], \ 'cmod': ['file.cmod'], @@ -869,6 +870,30 @@ func Test_d_file() call delete('Xfile.d') endfunc +func Test_dat_file() + filetype on + + call writefile(['&ACCESS'], 'datfile.dat') + split datfile.dat + call assert_equal('krl', &filetype) + bwipe! + call delete('datfile.dat') + + call writefile([' DEFDAT datfile'], 'datfile.Dat') + split datfile.Dat + call assert_equal('krl', &filetype) + bwipe! + call delete('datfile.Dat') + + call writefile(['', 'defdat datfile'], 'datfile.DAT') + split datfile.DAT + call assert_equal('krl', &filetype) + bwipe! + call delete('datfile.DAT') + + filetype off +endfunc + func Test_dep3patch_file() filetype on @@ -1311,6 +1336,30 @@ func Test_pp_file() filetype off endfunc +func Test_src_file() + filetype on + + call writefile(['&ACCESS'], 'srcfile.src') + split srcfile.src + call assert_equal('krl', &filetype) + bwipe! + call delete('srcfile.src') + + call writefile([' DEF srcfile()'], 'srcfile.Src') + split srcfile.Src + call assert_equal('krl', &filetype) + bwipe! + call delete('srcfile.Src') + + call writefile(['', 'global def srcfile()'], 'srcfile.SRC') + split srcfile.SRC + call assert_equal('krl', &filetype) + bwipe! + call delete('srcfile.SRC') + + filetype off +endfunc + func Test_tex_file() filetype on diff --git a/src/testdir/test_highlight.vim b/src/testdir/test_highlight.vim index 51a25242fe..3400052a7c 100644 --- a/src/testdir/test_highlight.vim +++ b/src/testdir/test_highlight.vim @@ -610,6 +610,14 @@ func Test_cursorcolumn_insert_on_tab() call TermWait(buf) call VerifyScreenDump(buf, 'Test_cursorcolumn_insert_on_tab_2', {}) + call term_sendkeys(buf, "\") + call TermWait(buf) + call VerifyScreenDump(buf, 'Test_cursorcolumn_insert_on_tab_3', {}) + + call term_sendkeys(buf, 'i') + call TermWait(buf) + call VerifyScreenDump(buf, 'Test_cursorcolumn_insert_on_tab_2', {}) + call StopVimInTerminal(buf) call delete('Xcuc_insert_on_tab') endfunc diff --git a/src/testdir/test_ins_complete.vim b/src/testdir/test_ins_complete.vim index 3712abe690..75ec03cb37 100644 --- a/src/testdir/test_ins_complete.vim +++ b/src/testdir/test_ins_complete.vim @@ -2132,4 +2132,23 @@ func Test_thesaurusfunc_callback() %bw! endfunc +func FooBarComplete(findstart, base) + if a:findstart + return col('.') - 1 + else + return ["Foo", "Bar", "}"] + endif +endfunc + +func Test_complete_smartindent() + new + setlocal smartindent completefunc=FooBarComplete + + exe "norm! o{\\\\}\\" + let result = getline(1,'$') + call assert_equal(['', '{','}',''], result) + bw! + delfunction! FooBarComplete +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_registers.vim b/src/testdir/test_registers.vim index 078b78dfdf..51543c00c1 100644 --- a/src/testdir/test_registers.vim +++ b/src/testdir/test_registers.vim @@ -759,6 +759,24 @@ func Test_record_in_select_mode() bwipe! endfunc +func Test_end_reg_executing() + nnoremap s + let @a = 's' + call feedkeys("@aqaq\", 'tx') + call assert_equal('', @a) + call assert_equal('', getline(1)) + + call setline(1, 'aaa') + nnoremap s qa + let @a = 'fa' + call feedkeys("@asq\", 'tx') + call assert_equal('', @a) + call assert_equal('aaa', getline(1)) + + nunmap s + bwipe! +endfunc + " Make sure that y_append is correctly reset " and the previous register is working as expected func Test_register_y_append_reset() diff --git a/src/version.c b/src/version.c index 7007411288..afa60a4b2b 100644 --- a/src/version.c +++ b/src/version.c @@ -761,6 +761,28 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 4710, +/**/ + 4709, +/**/ + 4708, +/**/ + 4707, +/**/ + 4706, +/**/ + 4705, +/**/ + 4704, +/**/ + 4703, +/**/ + 4702, +/**/ + 4701, +/**/ + 4700, /**/ 4699, /**/ diff --git a/src/window.c b/src/window.c index b14c074cba..622e9efb4f 100644 --- a/src/window.c +++ b/src/window.c @@ -2498,7 +2498,7 @@ win_close_buffer(win_T *win, int action, int abort_if_last) set_bufref(&bufref, curbuf); win->w_closing = TRUE; - close_buffer(win, win->w_buffer, action, abort_if_last, FALSE); + close_buffer(win, win->w_buffer, action, abort_if_last, TRUE); if (win_valid_any_tab(win)) win->w_closing = FALSE; // Make sure curbuf is valid. It can become invalid if 'bufhidden' is @@ -2819,7 +2819,7 @@ win_close_othertab(win_T *win, int free_buf, tabpage_T *tp) if (win->w_buffer != NULL) // Close the link to the buffer. close_buffer(win, win->w_buffer, free_buf ? DOBUF_UNLOAD : 0, - FALSE, FALSE); + FALSE, TRUE); // Careful: Autocommands may have closed the tab page or made it the // current tab page.