diff --git a/runtime/autoload/netrw.vim b/runtime/autoload/netrw.vim index d09299a583..0adcc65869 100644 --- a/runtime/autoload/netrw.vim +++ b/runtime/autoload/netrw.vim @@ -4,8 +4,8 @@ " Date: May 03, 2023 " Version: 173a " Last Change: {{{1 -" 2023 Nov 21 by Vim Project: ignore wildignore when expanding $COMSPEC (v173a) -" 2023 Nov 22 by Vim Project: fix handling of very long filename on longlist style (v173a) +" 2023 Nov 21 by Vim Project: ignore wildignore when expanding $COMSPEC (v173a) +" 2023 Nov 22 by Vim Project: fix handling of very long filename on longlist style (v173a) " 2024 Feb 19 by Vim Project: (announce adoption) " 2024 Feb 29 by Vim Project: handle symlinks in tree mode correctly " 2024 Apr 03 by Vim Project: detect filetypes for remote edited files @@ -26,6 +26,7 @@ " 2024 Sep 15 by Vim Project: more strict confirmation dialog (#15680) " 2024 Sep 19 by Vim Project: mf-selection highlight uses wrong pattern (#15700) " 2024 Sep 21 by Vim Project: remove extraneous closing bracket (#15718) +" 2024 Oct 21 by Vim Project: remove netrwFileHandlers (#15895) " }}} " Former Maintainer: Charles E Campbell " GetLatestVimScripts: 1075 1 :AutoInstall: netrw.vim @@ -5448,11 +5449,7 @@ fun! netrw#BrowseX(fname,remote) " execute the file handler " call Decho("execute the file handler (if any)",'~'.expand("")) - if exists("g:netrw_browsex_viewer") && g:netrw_browsex_viewer == '-' -" call Decho("(netrw#BrowseX) g:netrw_browsex_viewer<".g:netrw_browsex_viewer.">",'~'.expand("")) - let ret= netrwFileHandlers#Invoke(exten,fname) - - elseif exists("g:netrw_browsex_viewer") && executable(viewer) + if exists("g:netrw_browsex_viewer") && executable(viewer) " call Decho("(netrw#BrowseX) g:netrw_browsex_viewer<".g:netrw_browsex_viewer.">",'~'.expand("")) call s:NetrwExe("sil !".viewer." ".viewopt.s:ShellEscape(fname,1).redir) let ret= v:shell_error @@ -5518,17 +5515,13 @@ fun! netrw#BrowseX(fname,remote) " call Decho("(netrw#BrowseX) macunix and open",'~'.expand("")) call s:NetrwExe("sil !open ".s:ShellEscape(fname,1)." ".redir) let ret= v:shell_error - else - " netrwFileHandlers#Invoke() always returns 0 -" call Decho("(netrw#BrowseX) use netrwFileHandlers",'~'.expand("")) - let ret= netrwFileHandlers#Invoke(exten,fname) + call netrw#ErrorMsg(s:ERROR, "Couldn't find a program to open '".a:fname."'", 0) + let ret=0 endif - " if unsuccessful, attempt netrwFileHandlers#Invoke() if ret -" call Decho("(netrw#BrowseX) ret=".ret," indicates unsuccessful thus far",'~'.expand("")) - let ret= netrwFileHandlers#Invoke(exten,fname) + call netrw#ErrorMsg(s:ERROR, "Failed to open '".a:fname."'", 0) endif " restoring redraw! after external file handlers diff --git a/runtime/autoload/netrwFileHandlers.vim b/runtime/autoload/netrwFileHandlers.vim deleted file mode 100644 index 2b6f8f7a0f..0000000000 --- a/runtime/autoload/netrwFileHandlers.vim +++ /dev/null @@ -1,363 +0,0 @@ -" netrwFileHandlers: contains various extension-based file handlers for -" netrw's browsers' x command ("eXecute launcher") -" Maintainer: This runtime file is looking for a new maintainer. -" Original Author: Charles E. Campbell -" Date: Sep 18, 2020 -" Version: 11 -" Copyright: Copyright (C) 1999-2012 Charles E. Campbell {{{1 -" Permission is hereby granted to use and distribute this code, -" with or without modifications, provided that this copyright -" notice is copied with it. Like anything else that's free, -" netrwFileHandlers.vim is provided *as is* and comes with no -" warranty of any kind, either expressed or implied. In no -" event will the copyright holder be liable for any damages -" resulting from the use of this software. -" -" Rom 6:23 (WEB) For the wages of sin is death, but the free gift of God {{{1 -" is eternal life in Christ Jesus our Lord. - -" --------------------------------------------------------------------- -" Load Once: {{{1 -if exists("g:loaded_netrwFileHandlers") || &cp - finish -endif -let g:loaded_netrwFileHandlers= "v11" -if v:version < 702 - echohl WarningMsg - echo "***warning*** this version of netrwFileHandlers needs vim 7.2" - echohl Normal - finish -endif -let s:keepcpo= &cpo -set cpo&vim - -" --------------------------------------------------------------------- -" netrwFileHandlers#Invoke: {{{1 -fun! netrwFileHandlers#Invoke(exten,fname) -" call Dfunc("netrwFileHandlers#Invoke(exten<".a:exten."> fname<".a:fname.">)") - let exten= a:exten - " list of supported special characters. Consider rcs,v --- that can be - " supported with a NFH_rcsCOMMAv() handler - if exten =~ '[@:,$!=\-+%?;~]' - let specials= { -\ '@' : 'AT', -\ ':' : 'COLON', -\ ',' : 'COMMA', -\ '$' : 'DOLLAR', -\ '!' : 'EXCLAMATION', -\ '=' : 'EQUAL', -\ '-' : 'MINUS', -\ '+' : 'PLUS', -\ '%' : 'PERCENT', -\ '?' : 'QUESTION', -\ ';' : 'SEMICOLON', -\ '~' : 'TILDE'} - let exten= substitute(a:exten,'[@:,$!=\-+%?;~]','\=specials[submatch(0)]','ge') -" call Decho('fname<'.fname.'> done with dictionary') - endif - - if a:exten != "" && exists("*NFH_".exten) - " support user NFH_*() functions -" call Decho("let ret= netrwFileHandlers#NFH_".a:exten.'("'.fname.'")') - exe "let ret= NFH_".exten.'("'.a:fname.'")' - elseif a:exten != "" && exists("*s:NFH_".exten) - " use builtin-NFH_*() functions -" call Decho("let ret= netrwFileHandlers#NFH_".a:exten.'("'.fname.'")') - exe "let ret= s:NFH_".a:exten.'("'.a:fname.'")' - endif - -" call Dret("netrwFileHandlers#Invoke 0 : ret=".ret) - return 0 -endfun - -" --------------------------------------------------------------------- -" s:NFH_html: handles html when the user hits "x" when the {{{1 -" cursor is atop a *.html file -fun! s:NFH_html(pagefile) -" call Dfunc("s:NFH_html(".a:pagefile.")") - - let page= substitute(a:pagefile,'^','file://','') - - if executable("mozilla") -" call Decho("executing !mozilla ".page) - exe "!mozilla ".shellescape(page,1) - elseif executable("netscape") -" call Decho("executing !netscape ".page) - exe "!netscape ".shellescape(page,1) - else -" call Dret("s:NFH_html 0") - return 0 - endif - -" call Dret("s:NFH_html 1") - return 1 -endfun - -" --------------------------------------------------------------------- -" s:NFH_htm: handles html when the user hits "x" when the {{{1 -" cursor is atop a *.htm file -fun! s:NFH_htm(pagefile) -" call Dfunc("s:NFH_htm(".a:pagefile.")") - - let page= substitute(a:pagefile,'^','file://','') - - if executable("mozilla") -" call Decho("executing !mozilla ".page) - exe "!mozilla ".shellescape(page,1) - elseif executable("netscape") -" call Decho("executing !netscape ".page) - exe "!netscape ".shellescape(page,1) - else -" call Dret("s:NFH_htm 0") - return 0 - endif - -" call Dret("s:NFH_htm 1") - return 1 -endfun - -" --------------------------------------------------------------------- -" s:NFH_jpg: {{{1 -fun! s:NFH_jpg(jpgfile) -" call Dfunc("s:NFH_jpg(jpgfile<".a:jpgfile.">)") - - if executable("gimp") - exe "silent! !gimp -s ".shellescape(a:jpgfile,1) - elseif executable(expand("$SystemRoot")."/SYSTEM32/MSPAINT.EXE") -" call Decho("silent! !".expand("$SystemRoot")."/SYSTEM32/MSPAINT ".escape(a:jpgfile," []|'")) - exe "!".expand("$SystemRoot")."/SYSTEM32/MSPAINT ".shellescape(a:jpgfile,1) - else -" call Dret("s:NFH_jpg 0") - return 0 - endif - -" call Dret("s:NFH_jpg 1") - return 1 -endfun - -" --------------------------------------------------------------------- -" s:NFH_gif: {{{1 -fun! s:NFH_gif(giffile) -" call Dfunc("s:NFH_gif(giffile<".a:giffile.">)") - - if executable("gimp") - exe "silent! !gimp -s ".shellescape(a:giffile,1) - elseif executable(expand("$SystemRoot")."/SYSTEM32/MSPAINT.EXE") - exe "silent! !".expand("$SystemRoot")."/SYSTEM32/MSPAINT ".shellescape(a:giffile,1) - else -" call Dret("s:NFH_gif 0") - return 0 - endif - -" call Dret("s:NFH_gif 1") - return 1 -endfun - -" --------------------------------------------------------------------- -" s:NFH_png: {{{1 -fun! s:NFH_png(pngfile) -" call Dfunc("s:NFH_png(pngfile<".a:pngfile.">)") - - if executable("gimp") - exe "silent! !gimp -s ".shellescape(a:pngfile,1) - elseif executable(expand("$SystemRoot")."/SYSTEM32/MSPAINT.EXE") - exe "silent! !".expand("$SystemRoot")."/SYSTEM32/MSPAINT ".shellescape(a:pngfile,1) - else -" call Dret("s:NFH_png 0") - return 0 - endif - -" call Dret("s:NFH_png 1") - return 1 -endfun - -" --------------------------------------------------------------------- -" s:NFH_pnm: {{{1 -fun! s:NFH_pnm(pnmfile) -" call Dfunc("s:NFH_pnm(pnmfile<".a:pnmfile.">)") - - if executable("gimp") - exe "silent! !gimp -s ".shellescape(a:pnmfile,1) - elseif executable(expand("$SystemRoot")."/SYSTEM32/MSPAINT.EXE") - exe "silent! !".expand("$SystemRoot")."/SYSTEM32/MSPAINT ".shellescape(a:pnmfile,1) - else -" call Dret("s:NFH_pnm 0") - return 0 - endif - -" call Dret("s:NFH_pnm 1") - return 1 -endfun - -" --------------------------------------------------------------------- -" s:NFH_bmp: visualize bmp files {{{1 -fun! s:NFH_bmp(bmpfile) -" call Dfunc("s:NFH_bmp(bmpfile<".a:bmpfile.">)") - - if executable("gimp") - exe "silent! !gimp -s ".a:bmpfile - elseif executable(expand("$SystemRoot")."/SYSTEM32/MSPAINT.EXE") - exe "silent! !".expand("$SystemRoot")."/SYSTEM32/MSPAINT ".shellescape(a:bmpfile,1) - else -" call Dret("s:NFH_bmp 0") - return 0 - endif - -" call Dret("s:NFH_bmp 1") - return 1 -endfun - -" --------------------------------------------------------------------- -" s:NFH_pdf: visualize pdf files {{{1 -fun! s:NFH_pdf(pdf) -" call Dfunc("s:NFH_pdf(pdf<".a:pdf.">)") - if executable("gs") - exe 'silent! !gs '.shellescape(a:pdf,1) - elseif executable("pdftotext") - exe 'silent! pdftotext -nopgbrk '.shellescape(a:pdf,1) - else -" call Dret("s:NFH_pdf 0") - return 0 - endif - -" call Dret("s:NFH_pdf 1") - return 1 -endfun - -" --------------------------------------------------------------------- -" s:NFH_doc: visualize doc files {{{1 -fun! s:NFH_doc(doc) -" call Dfunc("s:NFH_doc(doc<".a:doc.">)") - - if executable("oowriter") - exe 'silent! !oowriter '.shellescape(a:doc,1) - redraw! - else -" call Dret("s:NFH_doc 0") - return 0 - endif - -" call Dret("s:NFH_doc 1") - return 1 -endfun - -" --------------------------------------------------------------------- -" s:NFH_sxw: visualize sxw files {{{1 -fun! s:NFH_sxw(sxw) -" call Dfunc("s:NFH_sxw(sxw<".a:sxw.">)") - - if executable("oowriter") - exe 'silent! !oowriter '.shellescape(a:sxw,1) - redraw! - else -" call Dret("s:NFH_sxw 0") - return 0 - endif - -" call Dret("s:NFH_sxw 1") - return 1 -endfun - -" --------------------------------------------------------------------- -" s:NFH_xls: visualize xls files {{{1 -fun! s:NFH_xls(xls) -" call Dfunc("s:NFH_xls(xls<".a:xls.">)") - - if executable("oocalc") - exe 'silent! !oocalc '.shellescape(a:xls,1) - redraw! - else -" call Dret("s:NFH_xls 0") - return 0 - endif - -" call Dret("s:NFH_xls 1") - return 1 -endfun - -" --------------------------------------------------------------------- -" s:NFH_ps: handles PostScript files {{{1 -fun! s:NFH_ps(ps) -" call Dfunc("s:NFH_ps(ps<".a:ps.">)") - if executable("gs") -" call Decho("exe silent! !gs ".a:ps) - exe "silent! !gs ".shellescape(a:ps,1) - redraw! - elseif executable("ghostscript") -" call Decho("exe silent! !ghostscript ".a:ps) - exe "silent! !ghostscript ".shellescape(a:ps,1) - redraw! - elseif executable("gswin32") -" call Decho("exe silent! !gswin32 ".shellescape(a:ps,1)) - exe "silent! !gswin32 ".shellescape(a:ps,1) - redraw! - else -" call Dret("s:NFH_ps 0") - return 0 - endif - -" call Dret("s:NFH_ps 1") - return 1 -endfun - -" --------------------------------------------------------------------- -" s:NFH_eps: handles encapsulated PostScript files {{{1 -fun! s:NFH_eps(eps) -" call Dfunc("s:NFH_eps()") - if executable("gs") - exe "silent! !gs ".shellescape(a:eps,1) - redraw! - elseif executable("ghostscript") - exe "silent! !ghostscript ".shellescape(a:eps,1) - redraw! - elseif executable("ghostscript") - exe "silent! !ghostscript ".shellescape(a:eps,1) - redraw! - elseif executable("gswin32") - exe "silent! !gswin32 ".shellescape(a:eps,1) - redraw! - else -" call Dret("s:NFH_eps 0") - return 0 - endif -" call Dret("s:NFH_eps 0") - return 1 -endfun - -" --------------------------------------------------------------------- -" s:NFH_fig: handles xfig files {{{1 -fun! s:NFH_fig(fig) -" call Dfunc("s:NFH_fig()") - if executable("xfig") - exe "silent! !xfig ".a:fig - redraw! - else -" call Dret("s:NFH_fig 0") - return 0 - endif - -" call Dret("s:NFH_fig 1") - return 1 -endfun - -" --------------------------------------------------------------------- -" s:NFH_obj: handles tgif's obj files {{{1 -fun! s:NFH_obj(obj) -" call Dfunc("s:NFH_obj()") - if has("unix") && executable("tgif") - exe "silent! !tgif ".a:obj - redraw! - else -" call Dret("s:NFH_obj 0") - return 0 - endif - -" call Dret("s:NFH_obj 1") - return 1 -endfun - -let &cpo= s:keepcpo -unlet s:keepcpo -" --------------------------------------------------------------------- -" Modelines: {{{1 -" vim: fdm=marker diff --git a/runtime/autoload/typst.vim b/runtime/autoload/typst.vim index 55edd23928..baf765a30b 100644 --- a/runtime/autoload/typst.vim +++ b/runtime/autoload/typst.vim @@ -1,6 +1,6 @@ " Language: Typst " Maintainer: Gregory Anders -" Last Change: 2024-07-14 +" Last Change: 2024 Oct 21 " Based on: https://github.com/kaarmu/typst.vim function! typst#indentexpr() abort @@ -31,6 +31,31 @@ function! typst#indentexpr() abort return l:ind endfunction +function typst#foldexpr() + let line = getline(v:lnum) + + " Whenever the user wants to fold nested headers under the parent + let nested = get(g:, "typst_foldnested", 1) + + " Regular headers + let depth = match(line, '\(^=\+\)\@<=\( .*$\)\@=') + + " Do not fold nested regular headers + if depth > 1 && !nested + let depth = 1 + endif + + if depth > 0 + " check syntax, it should be typstMarkupHeading + let syncode = synstack(v:lnum, 1) + if len(syncode) > 0 && synIDattr(syncode[0], 'name') ==# 'typstMarkupHeading' + return ">" . depth + endif + endif + + return "=" +endfunction + " Gets the previous non-blank line that is not a comment. function! s:get_prev_nonblank(lnum) abort let l:lnum = prevnonblank(a:lnum) diff --git a/runtime/compiler/cppcheck.vim b/runtime/compiler/cppcheck.vim index ed7c46e90f..20c906f412 100644 --- a/runtime/compiler/cppcheck.vim +++ b/runtime/compiler/cppcheck.vim @@ -1,7 +1,7 @@ " vim compiler file " Compiler: cppcheck (C++ static checker) " Maintainer: Vincent B. (twinside@free.fr) -" Last Change: 2024 Oct 4 by @Konfekt +" Last Change: 2024 oct 17 by @Konfekt if exists("cppcheck") finish @@ -11,6 +11,8 @@ let current_compiler = "cppcheck" let s:cpo_save = &cpo set cpo-=C +let s:slash = has('win32')? '\' : '/' + if !exists('g:c_cppcheck_params') let g:c_cppcheck_params = '--verbose --force --inline-suppr' \ ..' '..'--enable=warning,style,performance,portability,information,missingInclude' @@ -20,11 +22,11 @@ endif let &l:makeprg = 'cppcheck --quiet' \ ..' --template="{file}:{line}:{column}: {severity}: [{id}] {message} {callstack}"' - \ ..' '..get(b:, 'c_cppcheck_params', - \ g:c_cppcheck_params..' '..(&filetype ==# 'cpp' ? ' --language=c++' : '')) + \ ..' '..get(b:, 'c_cppcheck_params', get(g:, 'c_cppcheck_params', (&filetype ==# 'cpp' ? ' --language=c++' : ''))) \ ..' '..get(b:, 'c_cppcheck_includes', get(g:, 'c_cppcheck_includes', \ (filereadable('compile_commands.json') ? '--project=compile_commands.json' : - \ (empty(&path) ? '' : '-I')..join(map(filter(split(&path, ','), 'isdirectory(v:val)'),'shellescape(v:val)'), ' -I')))) + \ (!empty(glob('*'..s:slash..'compile_commands.json', 1, 1)) ? '--project='..glob('*'..s:slash..'compile_commands.json', 1, 1)[0] : + \ (empty(&path) ? '' : '-I')..join(map(filter(split(&path, ','), 'isdirectory(v:val)'),'shellescape(v:val)'), ' -I'))))) silent CompilerSet makeprg CompilerSet errorformat= diff --git a/runtime/doc/builtin.txt b/runtime/doc/builtin.txt index bdf9962155..e0a10996a2 100644 --- a/runtime/doc/builtin.txt +++ b/runtime/doc/builtin.txt @@ -1,4 +1,4 @@ -*builtin.txt* For Vim version 9.1. Last change: 2024 Oct 14 +*builtin.txt* For Vim version 9.1. Last change: 2024 Oct 16 VIM REFERENCE MANUAL by Bram Moolenaar @@ -11978,7 +11978,7 @@ wildmenumode() *wildmenumode()* For example to make work like in wildmode, use: > :cnoremap wildmenumode() ? "\\" : "\" < - (Note, this needs the 'wildcharm' option set appropriately). + (Note: this needs the 'wildcharm' option set appropriately). Return type: |Number| diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index 9d1957293c..309bd00498 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -1,4 +1,4 @@ -*eval.txt* For Vim version 9.1. Last change: 2024 Jul 28 +*eval.txt* For Vim version 9.1. Last change: 2024 Oct 22 VIM REFERENCE MANUAL by Bram Moolenaar @@ -2223,7 +2223,8 @@ v:fcs_choice What should happen after a |FileChangedShell| event was *v:fname* *fname-variable* v:fname When evaluating 'includeexpr': the file name that was - detected. Empty otherwise. + detected. When evaluating 'findexpr': the argument passed to + the |:find| command. Empty otherwise. *v:fname_in* *fname_in-variable* v:fname_in The name of the input file. Valid while evaluating: diff --git a/runtime/doc/filetype.txt b/runtime/doc/filetype.txt index 252551c359..be3ba021d0 100644 --- a/runtime/doc/filetype.txt +++ b/runtime/doc/filetype.txt @@ -1,4 +1,4 @@ -*filetype.txt* For Vim version 9.1. Last change: 2024 Oct 05 +*filetype.txt* For Vim version 9.1. Last change: 2024 Oct 21 VIM REFERENCE MANUAL by Bram Moolenaar @@ -939,6 +939,19 @@ TYPST *ft-typst-plugin* *g:typst_conceal* When |TRUE| the Typst filetype plugin will set the 'conceallevel' option to 2. + *g:typst_folding* +When |TRUE| the Typst filetype plugin will fold headings. (default: |FALSE|) + +To enable: > + let g:typst_folding = 1 +< + *g:typst_foldnested* +When |TRUE| the Typst filetype plugin will fold nested heading under their parents +(default: |TRUE|) + +To disable: > + let g:typst_foldnested = 0 +< VIM *ft-vim-plugin* The Vim filetype plugin defines mappings to move to the start and end of diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index 2bd9bdf420..5fb1f824c4 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -1,4 +1,4 @@ -*options.txt* For Vim version 9.1. Last change: 2024 Oct 14 +*options.txt* For Vim version 9.1. Last change: 2024 Oct 22 VIM REFERENCE MANUAL by Bram Moolenaar @@ -3418,7 +3418,7 @@ A jump table for the options with a short description can be found at |Q_op|. *'fileformat'* *'ff'* 'fileformat' 'ff' string (MS-Windows default: "dos", - Unix, macOS default: "unix") + Unix default: "unix") local to buffer This gives the of the current buffer, which is used for reading/writing the buffer from/to a file: @@ -3441,7 +3441,7 @@ A jump table for the options with a short description can be found at |Q_op|. *'fileformats'* *'ffs'* 'fileformats' 'ffs' string (default: Vim+Vi MS-Windows: "dos,unix", - Vim Unix, macOS: "unix,dos", + Vim Unix: "unix,dos", Vi Cygwin: "unix,dos", Vi others: "") global @@ -3567,6 +3567,51 @@ A jump table for the options with a short description can be found at |Q_op|. eob EndOfBuffer |hl-EndOfBuffer| lastline NonText |hl-NonText| + *'findexpr'* *'fexpr'* *E1514* +'findexpr' 'fexpr' string (default "") + global or local to buffer |global-local| + {not available when compiled without the |+eval| + feature} + Expression that is evaluated to obtain the filename(s) for the |:find| + command. When this option is empty, the internal |file-searching| + mechanism is used. + + While evaluating the expression, the |v:fname| variable is set to the + argument of the |:find| command. + + The expression is evaluated only once per |:find| command invocation. + The expression can process all the directories specified in 'path'. + + If a match is found, the expression should return a |List| containing + one or more file names. If a match is not found, the expression + should return an empty List. + + If any errors are encountered during the expression evaluation, an + empty List is used as the return value. + + Using a function call without arguments is faster |expr-option-function| + + It is not allowed to change text or jump to another window while + evaluating 'findexpr' |textlock|. + + This option cannot be set from a |modeline| or in the |sandbox|, for + security reasons. + + Examples: +> + " Use glob() + func FindExprGlob() + return glob(v:fname, v:false, v:true) + endfunc + set findexpr=FindExprGlob() + + " Use the 'git ls-files' output + func FindGitFiles() + let fnames = systemlist('git ls-files') + return fnames->filter('v:val =~? v:fname') + endfunc + set findexpr=FindGitFiles() +< *'fixendofline'* *'fixeol'* *'nofixendofline'* *'nofixeol'* 'fixendofline' 'fixeol' boolean (default on) local to buffer @@ -5011,7 +5056,7 @@ A jump table for the options with a short description can be found at |Q_op|. set and to the Vim default value when 'compatible' is reset. *'isprint'* *'isp'* -'isprint' 'isp' string (default for Win32 and macOS: +'isprint' 'isp' string (default for Win32 and VMS: "@,~-255"; otherwise: "@,161-255") global The characters given by this option are displayed directly on the @@ -6857,7 +6902,7 @@ A jump table for the options with a short description can be found at |Q_op|. < *'runtimepath'* *'rtp'* *vimfiles* 'runtimepath' 'rtp' string (default: - Unix, macOS: "$HOME/.vim or + Unix: "$HOME/.vim or $XDG_CONFIG_HOME/vim, $VIM/vimfiles, $VIMRUNTIME, @@ -6873,9 +6918,6 @@ A jump table for the options with a short description can be found at |Q_op|. $VIMRUNTIME, $VIM/vimfiles/after, $HOME/vimfiles/after" - Classic Mac OS: "$VIM:vimfiles, - $VIMRUNTIME, - $VIM:vimfiles:after" Haiku: "$BE_USER_SETTINGS/vim, $VIM/vimfiles, $VIMRUNTIME, @@ -8837,7 +8879,9 @@ A jump table for the options with a short description can be found at |Q_op|. be restored if possible, see |X11|. When this option contains printf-style '%' items, they will be - expanded according to the rules used for 'statusline'. + expanded according to the rules used for 'statusline'. If it contains + an invalid '%' format, the value is used as-is and no error or warning + will be given when the value is set. This option cannot be set in a modeline when 'modelineexpr' is off. Example: > @@ -9199,7 +9243,6 @@ A jump table for the options with a short description can be found at |Q_op|. for Win32: "$HOME/vimfiles/view", for Unix: "$HOME/.vim/view" or "$XDG_CONFIG_HOME/vim/view" - for macOS: "$VIM/vimfiles/view", for VMS: "sys$login:vimfiles/view") global {not available when compiled without the |+mksession| diff --git a/runtime/doc/pi_netrw.txt b/runtime/doc/pi_netrw.txt index 1271bb689b..dd73ed2637 100644 --- a/runtime/doc/pi_netrw.txt +++ b/runtime/doc/pi_netrw.txt @@ -1,4 +1,4 @@ -*pi_netrw.txt* For Vim version 9.1. Last change: 2024 Jul 13 +*pi_netrw.txt* For Vim version 9.1. Last change: 2024 Oct 21 ------------------------------------------------ NETRW REFERENCE MANUAL by Charles E. Campbell @@ -1471,7 +1471,6 @@ permission to remove a file, it will issue an error message. *netrw-gx* CUSTOMIZING BROWSING WITH A SPECIAL HANDLER *netrw-x* *netrw-handler* {{{2 - (also see |netrw_filehandler|) Certain files, such as html, gif, jpeg, (word/office) doc, etc, files, are best seen with a special handler (ie. a tool provided with your computer's @@ -1490,21 +1489,12 @@ Netrw determines which special handler by the following method: < or > :let g:netrw_browsex_viewer= "xdg-open" < - If g:netrw_browsex_viewer == '-', then netrwFileHandlers#Invoke() will be - used instead (see |netrw_filehandler|). - If the viewer you wish to use does not support handling of a remote URL directory, set |g:netrw_browsex_support_remote| to 0. * for Windows 32 or 64, the URL and FileProtocolHandler dlls are used. * for Gnome (with gnome-open): gnome-open is used. * for KDE (with kfmclient) : kfmclient is used * for Mac OS X : open is used. - * otherwise the netrwFileHandler plugin is used. - -The file's suffix is used by these various approaches to determine an -appropriate application to use to "handle" these files. Such things as -OpenOffice (*.sfx), visualization (*.jpg, *.gif, etc), and PostScript (*.ps, -*.eps) can be handled. The gx mapping extends to all buffers; apply "gx" while atop a word and netrw will apply a special handler to it (like "x" works when in a netrw buffer). @@ -1521,46 +1511,6 @@ Associated setting variables: |g:netrw_nogx| prevent gx map while editing |g:netrw_suppress_gx_mesg| controls gx's suppression of browser messages - *netrw_filehandler* - -When |g:netrw_browsex_viewer| exists and is "-", then netrw will attempt to -handle the special file with a vim function. The "x" map applies a function -to a file, based on its extension. Of course, the handler function must exist -for it to be called! -> - Ex. mypgm.html x -> NFH_html("scp://user@host/some/path/mypgm.html") - -< Users may write their own netrw File Handler functions to - support more suffixes with special handling. See - for examples on how to make - file handler functions. As an example: > - - " NFH_suffix(filename) - fun! NFH_suffix(filename) - ..do something special with filename.. - endfun -< -These functions need to be defined in some file in your .vim/plugin -(vimfiles\plugin) directory. Vim's function names may not have punctuation -characters (except for the underscore) in them. To support suffices that -contain such characters, netrw will first convert the suffix using the -following table: > - - @ -> AT ! -> EXCLAMATION % -> PERCENT - : -> COLON = -> EQUAL ? -> QUESTION - , -> COMMA - -> MINUS ; -> SEMICOLON - $ -> DOLLAR + -> PLUS ~ -> TILDE -< -So, for example: > - - file.rcs,v -> NFH_rcsCOMMAv() -< -If more such translations are necessary, please send me email: > - NcampObell@SdrPchip.AorgM-NOSPAM -with a request. (remove the embedded NOSPAM first) - -Associated setting variable: |g:netrw_browsex_viewer| - *netrw-curdir* DELETING BOOKMARKS *netrw-mB* {{{2 @@ -2583,12 +2533,7 @@ your browsing preferences. (see also: |netrw-settings|) *g:netrw_browsex_viewer* specify user's preference for a viewer: > "kfmclient exec" "gnome-open" -< If > - "-" -< is used, then netrwFileHandler() will look for - a script/function to handle the given - extension. (see |netrw_filehandler|). - +< *g:netrw_browsex_support_remote* specify if the specified viewer supports a remote URL. (see |netrw-handler|). diff --git a/runtime/doc/quickref.txt b/runtime/doc/quickref.txt index 29a99a1bf8..851cd2e388 100644 --- a/runtime/doc/quickref.txt +++ b/runtime/doc/quickref.txt @@ -1,4 +1,4 @@ -*quickref.txt* For Vim version 9.1. Last change: 2024 Mar 03 +*quickref.txt* For Vim version 9.1. Last change: 2024 Oct 22 VIM REFERENCE MANUAL by Bram Moolenaar @@ -709,6 +709,7 @@ Short explanation of each option: *option-list* 'fileignorecase' 'fic' ignore case when using file names 'filetype' 'ft' type of file, used for autocommands 'fillchars' 'fcs' characters to use for displaying special items +'findexpr' 'fexpr' expression to evaluate for |:find| 'fixendofline' 'fixeol' make sure last line in file has 'fkmap' 'fk' obsolete option for Farsi 'foldclose' 'fcl' close a fold when the cursor leaves it diff --git a/runtime/doc/repeat.txt b/runtime/doc/repeat.txt index 73d6458d55..d85e580f51 100644 --- a/runtime/doc/repeat.txt +++ b/runtime/doc/repeat.txt @@ -1,4 +1,4 @@ -*repeat.txt* For Vim version 9.1. Last change: 2024 Oct 05 +*repeat.txt* For Vim version 9.1. Last change: 2024 Oct 16 VIM REFERENCE MANUAL by Bram Moolenaar @@ -1398,9 +1398,9 @@ For example, to profile the one_script.vim script file: > clear the profiling statistics and start profiling again. :prof[ile] pause - Don't profile until the following `:profile continue`. Can be - used when doing something that should not be counted (e.g., an - external command). Does not nest. + Stop profiling until the next `:profile continue` command. + Can be used when doing something that should not be counted + (e.g., an external command). Does not nest. :prof[ile] continue Continue profiling after `:profile pause`. diff --git a/runtime/doc/syntax.txt b/runtime/doc/syntax.txt index 2acb59f9fd..9cea4f85d0 100644 --- a/runtime/doc/syntax.txt +++ b/runtime/doc/syntax.txt @@ -1,4 +1,4 @@ -*syntax.txt* For Vim version 9.1. Last change: 2024 Oct 13 +*syntax.txt* For Vim version 9.1. Last change: 2024 Oct 22 VIM REFERENCE MANUAL by Bram Moolenaar @@ -5309,12 +5309,15 @@ of colors by using the `:colorscheme` command, for example: > This is basically the same as > :echo g:colors_name < In case g:colors_name has not been defined :colo will - output "default". When compiled without the |+eval| - feature it will output "unknown". + output "default". Its palette is defined in the file + "$VIMRUNTIME/syntax/syncolor.vim" and is based on + legacy versions of peachpuff and desert. When compiled + without the |+eval| feature it will output "unknown". :colo[rscheme] {name} Load color scheme {name}. This searches 'runtimepath' for the file "colors/{name}.vim". The first one that is found is loaded. + Use `:colo default` to load the default colorscheme. Also searches all plugins in 'packpath', first below "start" and then under "opt". @@ -6139,7 +6142,8 @@ This will set the "w:current_syntax" variable to "foo". The value of restoring "b:current_syntax", since the syntax files do set "b:current_syntax". The value set by the syntax file is assigned to "w:current_syntax". -Note: This resets the 'spell', 'spellcapcheck' and 'spellfile' options. +Note: This resets the 'spell', 'spellcapcheck', 'spellfile' and 'spelloptions' +options. Once a window has its own syntax, syntax commands executed from other windows on the same buffer (including :syntax clear) have no effect. Conversely, diff --git a/runtime/doc/tags b/runtime/doc/tags index 809f8dbd86..dc038116d8 100644 --- a/runtime/doc/tags +++ b/runtime/doc/tags @@ -271,6 +271,7 @@ $quote eval.txt /*$quote* 'fenc' options.txt /*'fenc'* 'fencs' options.txt /*'fencs'* 'fex' options.txt /*'fex'* +'fexpr' options.txt /*'fexpr'* 'ff' options.txt /*'ff'* 'ffs' options.txt /*'ffs'* 'fic' options.txt /*'fic'* @@ -281,6 +282,7 @@ $quote eval.txt /*$quote* 'fileignorecase' options.txt /*'fileignorecase'* 'filetype' options.txt /*'filetype'* 'fillchars' options.txt /*'fillchars'* +'findexpr' options.txt /*'findexpr'* 'fixendofline' options.txt /*'fixendofline'* 'fixeol' options.txt /*'fixeol'* 'fk' options.txt /*'fk'* @@ -4626,6 +4628,7 @@ E1510 change.txt /*E1510* E1511 options.txt /*E1511* E1512 options.txt /*E1512* E1513 message.txt /*E1513* +E1514 options.txt /*E1514* E152 helphelp.txt /*E152* E153 helphelp.txt /*E153* E154 helphelp.txt /*E154* @@ -7849,6 +7852,8 @@ g:typescript_host_keyword syntax.txt /*g:typescript_host_keyword* g:typst_cmd quickfix.txt /*g:typst_cmd* g:typst_conceal filetype.txt /*g:typst_conceal* g:typst_embedded_languages syntax.txt /*g:typst_embedded_languages* +g:typst_folding filetype.txt /*g:typst_folding* +g:typst_foldnested filetype.txt /*g:typst_foldnested* g:var eval.txt /*g:var* g:vim_indent indent.txt /*g:vim_indent* g:vim_indent_cont indent.txt /*g:vim_indent_cont* @@ -9286,7 +9291,6 @@ netrw-write pi_netrw.txt /*netrw-write* netrw-x pi_netrw.txt /*netrw-x* netrw-xfer pi_netrw.txt /*netrw-xfer* netrw.vim pi_netrw.txt /*netrw.vim* -netrw_filehandler pi_netrw.txt /*netrw_filehandler* netterm-mouse options.txt /*netterm-mouse* network pi_netrw.txt /*network* new() vim9class.txt /*new()* diff --git a/runtime/doc/version9.txt b/runtime/doc/version9.txt index 400ccd74ae..af180a2238 100644 --- a/runtime/doc/version9.txt +++ b/runtime/doc/version9.txt @@ -1,4 +1,4 @@ -*version9.txt* For Vim version 9.1. Last change: 2024 Oct 14 +*version9.txt* For Vim version 9.1. Last change: 2024 Oct 22 VIM REFERENCE MANUAL by Bram Moolenaar @@ -41649,6 +41649,8 @@ Options: ~ 'completeitemalign' Order of |complete-items| in Insert mode completion popup +'findexpr' Vim expression to obtain the results for a |:find| + command 'winfixbuf' Keep buffer focused in a window 'tabclose' Which tab page to focus after closing a tab page 't_xo' Terminal uses XON/XOFF handshaking (e.g. vt420) diff --git a/runtime/filetype.vim b/runtime/filetype.vim index edc8d5a2c2..618d30671c 100644 --- a/runtime/filetype.vim +++ b/runtime/filetype.vim @@ -283,7 +283,7 @@ au BufNewFile,BufRead *.blade.php setf blade au BufNewFile,BufRead *.bl setf blank " Bitbake -au BufNewFile,BufRead *.bb,*.bbappend,*.bbclass,*/build/conf/*.conf,*/meta{-*,}/conf/*.conf setf bitbake +au BufNewFile,BufRead *.bb,*.bbappend,*.bbclass,*/build/conf/*.conf,*/meta{-*,}/conf/*.conf,*/project-spec/configs/*.conf setf bitbake " Blkid cache file au BufNewFile,BufRead */etc/blkid.tab,*/etc/blkid.tab.old setf xml @@ -570,6 +570,9 @@ au BufNewFile,BufRead *.dsp call dist#ft#FTdsp() au BufNewFile,BufRead *.xcu,*.xlb,*.xlc,*.xba setf xml au BufNewFile,BufRead psprint.conf,sofficerc setf dosini +" Libtool files +au BufNewFile,BufRead *.lo,*.la,*.lai setf sh + " Lynx config files au BufNewFile,BufRead lynx.cfg setf lynx @@ -2815,7 +2818,7 @@ au BufNewFile,BufRead xorg.conf,xorg.conf-4 let b:xf86conf_xfree86_version = 4 | au BufNewFile,BufRead */etc/xinetd.conf setf xinetd " Xilinx Vivado/Vitis project files and block design files -au BufNewFile,BufRead *.xpr,*.xpfm,*.spfm,*.bxml setf xml +au BufNewFile,BufRead *.xpr,*.xpfm,*.spfm,*.bxml,*.mmi setf xml au BufNewFile,BufRead *.bd,*.bda,*.xci setf json " XS Perl extension interface language diff --git a/runtime/ftplugin/typst.vim b/runtime/ftplugin/typst.vim index 895fc688d9..3841e427f3 100644 --- a/runtime/ftplugin/typst.vim +++ b/runtime/ftplugin/typst.vim @@ -1,7 +1,7 @@ " Vim filetype plugin file " Language: Typst " Maintainer: Gregory Anders -" Last Change: 2024 Oct 04 +" Last Change: 2024 Oct 21 " Based on: https://github.com/kaarmu/typst.vim if exists('b:did_ftplugin') @@ -21,6 +21,12 @@ if get(g:, 'typst_conceal', 0) let b:undo_ftplugin .= ' cole<' endif +if has("folding") && get(g:, 'typst_folding', 0) + setlocal foldexpr=typst#foldexpr() + setlocal foldmethod=expr + let b:undo_ftplugin .= "|setl foldexpr< foldmethod<" +endif + if !exists('current_compiler') compiler typst let b:undo_ftplugin ..= "| compiler make" diff --git a/runtime/syntax/help.vim b/runtime/syntax/help.vim index dd45afdfe4..98668e5e9d 100644 --- a/runtime/syntax/help.vim +++ b/runtime/syntax/help.vim @@ -1,7 +1,7 @@ " Vim syntax file " Language: Vim help file " Maintainer: The Vim Project -" Last Change: 2024 Oct 08 +" Last Change: 2024 Oct 16 " Former Maintainer: Bram Moolenaar " Quit when a (custom) syntax file was already loaded @@ -48,7 +48,8 @@ syn match helpOption "'[a-z]\{2,\}'" syn match helpOption "'t_..'" syn match helpNormal "'ab'" syn match helpCommand "`[^` \t]\+`"hs=s+1,he=e-1 contains=helpBacktick -syn match helpCommand "\(^\|[^a-z"[]\)\zs`[^`]\+`\ze\([^a-z\t."']\|$\)"hs=s+1,he=e-1 contains=helpBacktick +" doesn't allow a . directly after an ending backtick. See :helpgrep `[^`,]\+ [^`,]\+`\. +syn match helpCommand "\(^\|[^a-z"[]\)\zs`[^`]\+`\ze\([^a-z\t."']\|[.?!]\?$\)"hs=s+1,he=e-1 contains=helpBacktick syn match helpHeader "\s*\zs.\{-}\ze\s\=\~$" nextgroup=helpIgnore syn match helpGraphic ".* \ze`$" nextgroup=helpIgnore if has("conceal") @@ -57,6 +58,7 @@ else syn match helpIgnore "." contained endif syn keyword helpNote note Note NOTE note: Note: NOTE: Notes Notes: +syn match helpNote "\c(note\(:\|\>\)"ms=s+1 syn keyword helpWarning WARNING WARNING: Warning: syn keyword helpDeprecated DEPRECATED DEPRECATED: Deprecated: syn match helpSpecial "\" @@ -69,6 +71,10 @@ syn match helpSpecial "\[N]" syn match helpSpecial "N N"he=s+1 syn match helpSpecial "Nth"me=e-2 syn match helpSpecial "N-1"me=e-2 +" highlighting N for :resize in windows.txt +syn match helpSpecial "] -N\>"ms=s+3 +syn match helpSpecial "+N\>"ms=s+1 +syn match helpSpecial "\[+-]N\>"ms=s+4 " highlighting N of cinoptions-values in indent.txt syn match helpSpecial "^\t-\?\zsNs\?\s"me=s+1 " highlighting N of cinoptions-values in indent.txt @@ -145,7 +151,7 @@ syn match helpUnderlined "\t[* ]Underlined\t\+[a-z].*" syn match helpError "\t[* ]Error\t\+[a-z].*" syn match helpTodo "\t[* ]Todo\t\+[a-z].*" -syn match helpURL `\v<(((https?|ftp|gopher)://|(mailto|file|news):)[^' <>"]+|(www|web|w3)[a-z0-9_-]*\.[a-z0-9._-]+\.[^' <>"]+)[a-zA-Z0-9/]` +syn match helpURL `\v<(((https?|ftp|gopher)://|(mailto|file|news):)[^'" \t<>{}]+|(www|web|w3)[a-z0-9_-]*\.[a-z0-9._-]+\.[^'" \t<>{}]+)[a-zA-Z0-9/]` syn match helpDiffAdded "\t[* ]Added\t\+[a-z].*" syn match helpDiffChanged "\t[* ]Changed\t\+[a-z].*" @@ -157,17 +163,6 @@ if s:i > 0 exe "runtime syntax/help_" . strpart(expand("%"), s:i + 1, 2) . ".vim" endif -" Italian -if v:lang =~ '\' || v:lang =~ '_IT\>' || v:lang =~? "italian" - syn keyword helpNote nota Nota NOTA nota: Nota: NOTA: notare Notare NOTARE notare: Notare: NOTARE: - syn match helpSpecial "Nma"me=e-2 - syn match helpSpecial "Nme"me=e-2 - syn match helpSpecial "Nmi"me=e-2 - syn match helpSpecial "Nmo"me=e-2 - syn match helpSpecial "\[interv.]" - syn region helpNotVi start="{non" start="{solo" start="{disponibile" end="}" contains=helpLeadBlank,helpHyperTextJump -endif - syn sync minlines=40 diff --git a/runtime/syntax/help_it.vim b/runtime/syntax/help_it.vim new file mode 100644 index 0000000000..e76851d446 --- /dev/null +++ b/runtime/syntax/help_it.vim @@ -0,0 +1,17 @@ +" Vim syntax file +" Language: Italian Vim program help files *.itx +" Maintainer: The Vim Project +" Last Change: 2024 Oct 16 +" +" This script is sourced from syntax/help.vim. + +syn keyword helpNote nota Nota NOTA nota: Nota: NOTA: notare Notare NOTARE notare: Notare: NOTARE: +syn match helpNote "\c(nota\(:\|\>\)"ms=s+1 +syn match helpSpecial "Nma"me=e-2 +syn match helpSpecial "Nme"me=e-2 +syn match helpSpecial "Nmi"me=e-2 +syn match helpSpecial "Nmo"me=e-2 +syn match helpSpecial "\[interv.]" +syn region helpNotVi start="{non" start="{solo" start="{disponibile" end="}" contains=helpLeadBlank,helpHyperTextJump + +" vim: ts=8 sw=2 diff --git a/runtime/syntax/jinja.vim b/runtime/syntax/jinja.vim index 6000855ff7..fa32c05f17 100644 --- a/runtime/syntax/jinja.vim +++ b/runtime/syntax/jinja.vim @@ -2,8 +2,9 @@ " Language: Jinja " Maintainer: Gregory Anders " Upstream: https://gitlab.com/HiPhish/jinja.vim +" Last Change: 2024 Oct 16 -if exists('b:current_syntax') +if exists('b:current_syntax') && b:current_syntax =~? 'jinja' finish endif diff --git a/runtime/syntax/swayconfig.vim b/runtime/syntax/swayconfig.vim index d09d476a5a..94b9a913fc 100644 --- a/runtime/syntax/swayconfig.vim +++ b/runtime/syntax/swayconfig.vim @@ -3,7 +3,7 @@ " Original Author: Josef Litos (JosefLitos/i3config.vim) " Maintainer: James Eapen " Version: 1.2.4 -" Last Change: 2024-05-24 +" Last Change: 2024 Oct 17 " References: " http://i3wm.org/docs/userguide.html#configuring @@ -29,7 +29,7 @@ syn keyword i3ConfigConditionProp app_id pid shell contained syn keyword i3ConfigWorkspaceDir prev_on_output next_on_output contained -syn match i3ConfigBindArgument /--\(locked\|to-code\|no-repeat\|input-device=[^ '"]*\|no-warn\) / contained contains=i3ConfigShOper,@i3ConfigStrVar nextgroup=i3ConfigBindArgument,i3ConfigBindCombo +syn match i3ConfigBindArgument /--\(locked\|to-code\|no-repeat\|input-device=[^ '"]*\|no-warn\|inhibited\) / contained contains=i3ConfigShOper,@i3ConfigStrVar nextgroup=i3ConfigBindArgument,i3ConfigBindCombo syn region i3ConfigBindArgument start=/--input-device=['"]/ end=/\s/ contained contains=@i3ConfigIdent,i3ConfigShOper,i3ConfigString nextgroup=i3ConfigBindArgument,i3ConfigBindCombo syn region i3ConfigBindCombo matchgroup=i3ConfigParen start=/{$/ end=/^\s*}$/ contained contains=i3ConfigBindArgument,i3ConfigBindCombo,i3ConfigComment fold keepend extend diff --git a/runtime/syntax/testdir/viewdumps.vim b/runtime/syntax/testdir/viewdumps.vim index e1624ff622..9c4de1b930 100644 --- a/runtime/syntax/testdir/viewdumps.vim +++ b/runtime/syntax/testdir/viewdumps.vim @@ -21,4 +21,4 @@ set display=lastline ruler scrolloff=5 t_ZH= t_ZR= # Anticipate non-Latin-1 characters in "input/" files. set encoding=utf-8 termencoding=utf-8 -# vim:fdm=syntax:sw=2:ts=8:noet:nolist:nosta: +# vim:fdm=syntax:sw=2:ts=8:noet:nosta: diff --git a/src/Make_ami.mak b/src/Make_ami.mak index 09cdd3c173..42270f36ba 100644 --- a/src/Make_ami.mak +++ b/src/Make_ami.mak @@ -53,8 +53,8 @@ endif # OS specific compiler flags ifeq ($(UNM),AmigaOS) -LDFLAGS = -mcrt=clib2 -lauto -lm -lnet -CFLAGS += -DHAVE_FSYNC -D__USE_INLINE__ -mcrt=clib2 +LDFLAGS = -lauto +CFLAGS += -DHAVE_FSYNC -D__USE_INLINE__ else ifeq ($(UNM),AROS) LDFLAGS = -DHAVE_FSYNC -ldebug diff --git a/src/buffer.c b/src/buffer.c index ab42e94220..c3abce8d93 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -214,7 +214,7 @@ open_buffer( enter_buffer(curbuf); #ifdef FEAT_SYN_HL if (old_tw != curbuf->b_p_tw) - check_colorcolumn(curwin); + check_colorcolumn(NULL, curwin); #endif return FAIL; } @@ -1217,7 +1217,7 @@ handle_swap_exists(bufref_T *old_curbuf) #ifdef FEAT_SYN_HL if (old_tw != curbuf->b_p_tw) - check_colorcolumn(curwin); + check_colorcolumn(NULL, curwin); #endif } // If "old_curbuf" is NULL we are in big trouble here... @@ -1915,7 +1915,7 @@ set_curbuf(buf_T *buf, int action) enter_buffer(buf); #ifdef FEAT_SYN_HL if (old_tw != curbuf->b_p_tw) - check_colorcolumn(curwin); + check_colorcolumn(NULL, curwin); #endif } } @@ -2416,6 +2416,7 @@ free_buf_options( clear_string_option(&buf->b_p_fp); #if defined(FEAT_EVAL) clear_string_option(&buf->b_p_fex); + clear_string_option(&buf->b_p_fexpr); #endif #ifdef FEAT_CRYPT # ifdef FEAT_SODIUM diff --git a/src/charset.c b/src/charset.c index e02f719c1a..b4bc812fa8 100644 --- a/src/charset.c +++ b/src/charset.c @@ -13,6 +13,7 @@ # include // for towupper() and towlower() #endif +static int parse_isopt(char_u *var, buf_T *buf, int only_check); static int win_nolbr_chartabsize(chartabsize_T *cts, int *headp); static unsigned nr2hex(unsigned c); @@ -75,11 +76,8 @@ buf_init_chartab( int global) // FALSE: only set buf->b_chartab[] { int c; - int c2; char_u *p; int i; - int tilde; - int do_isalpha; if (global) { @@ -135,9 +133,7 @@ buf_init_chartab( if (buf->b_p_lisp) SET_CHARTAB(buf, '-'); - // Walk through the 'isident', 'iskeyword', 'isfname' and 'isprint' - // options Each option is a list of characters, character numbers or - // ranges, separated by commas, e.g.: "200-210,x,#-178,-" + // Walk through the 'isident', 'iskeyword', 'isfname' and 'isprint' options. for (i = global ? 0 : 3; i <= 3; ++i) { if (i == 0) @@ -149,114 +145,152 @@ buf_init_chartab( else // i == 3 p = buf->b_p_isk; // fourth round: 'iskeyword' - while (*p) + if (parse_isopt(p, buf, FALSE) == FAIL) + return FAIL; + } + + chartab_initialized = TRUE; + return OK; +} + +/** + * Checks the format for the option settings 'iskeyword', 'isident', 'isfname' + * or 'isprint'. + * Returns FAIL if has an error, OK otherwise. + */ + int +check_isopt(char_u *var) +{ + return parse_isopt(var, NULL, TRUE); +} + + static int +parse_isopt( + char_u *var, + buf_T *buf, + int only_check) // FALSE: refill g_chartab[] +{ + char_u *p = var; + int c; + int c2; + int tilde; + int do_isalpha; + int trail_comma; + + // Parses the 'isident', 'iskeyword', 'isfname' and 'isprint' options. + // Each option is a list of characters, character numbers or ranges, + // separated by commas, e.g.: "200-210,x,#-178,-" + while (*p) + { + tilde = FALSE; + do_isalpha = FALSE; + if (*p == '^' && p[1] != NUL) { - tilde = FALSE; - do_isalpha = FALSE; - if (*p == '^' && p[1] != NUL) - { - tilde = TRUE; - ++p; - } + tilde = TRUE; + ++p; + } + if (VIM_ISDIGIT(*p)) + c = getdigits(&p); + else if (has_mbyte) + c = mb_ptr2char_adv(&p); + else + c = *p++; + c2 = -1; + if (*p == '-' && p[1] != NUL) + { + ++p; if (VIM_ISDIGIT(*p)) - c = getdigits(&p); + c2 = getdigits(&p); else if (has_mbyte) - c = mb_ptr2char_adv(&p); + c2 = mb_ptr2char_adv(&p); else - c = *p++; - c2 = -1; - if (*p == '-' && p[1] != NUL) + c2 = *p++; + } + if (c <= 0 || c >= 256 || (c2 < c && c2 != -1) || c2 >= 256 + || !(*p == NUL || *p == ',')) + return FAIL; + + trail_comma = *p == ','; + p = skip_to_option_part(p); + if (trail_comma && *p == NUL) + // Trailing comma is not allowed. + return FAIL; + + if (only_check) + continue; + + if (c2 == -1) // not a range + { + /* + * A single '@' (not "@-@"): + * Decide on letters being ID/printable/keyword chars with + * standard function isalpha(). This takes care of locale for + * single-byte characters). + */ + if (c == '@') { - ++p; - if (VIM_ISDIGIT(*p)) - c2 = getdigits(&p); - else if (has_mbyte) - c2 = mb_ptr2char_adv(&p); - else - c2 = *p++; + do_isalpha = TRUE; + c = 1; + c2 = 255; } - if (c <= 0 || c >= 256 || (c2 < c && c2 != -1) || c2 >= 256 - || !(*p == NUL || *p == ',')) - return FAIL; + else + c2 = c; + } - if (c2 == -1) // not a range + while (c <= c2) + { + // Use the MB_ functions here, because isalpha() doesn't + // work properly when 'encoding' is "latin1" and the locale is + // "C". + if (!do_isalpha || MB_ISLOWER(c) || MB_ISUPPER(c)) { - /* - * A single '@' (not "@-@"): - * Decide on letters being ID/printable/keyword chars with - * standard function isalpha(). This takes care of locale for - * single-byte characters). - */ - if (c == '@') + if (var == p_isi) // (re)set ID flag { - do_isalpha = TRUE; - c = 1; - c2 = 255; + if (tilde) + g_chartab[c] &= ~CT_ID_CHAR; + else + g_chartab[c] |= CT_ID_CHAR; } - else - c2 = c; - } - while (c <= c2) - { - // Use the MB_ functions here, because isalpha() doesn't - // work properly when 'encoding' is "latin1" and the locale is - // "C". - if (!do_isalpha || MB_ISLOWER(c) || MB_ISUPPER(c)) + else if (var == p_isp) // (re)set printable { - if (i == 0) // (re)set ID flag + if ((c < ' ' || c > '~' + // For double-byte we keep the cell width, so + // that we can detect it from the first byte. + ) && !(enc_dbcs && MB_BYTE2LEN(c) == 2)) { if (tilde) - g_chartab[c] &= ~CT_ID_CHAR; - else - g_chartab[c] |= CT_ID_CHAR; - } - else if (i == 1) // (re)set printable - { - if ((c < ' ' || c > '~' - // For double-byte we keep the cell width, so - // that we can detect it from the first byte. - ) && !(enc_dbcs && MB_BYTE2LEN(c) == 2)) { - if (tilde) - { - g_chartab[c] = (g_chartab[c] & ~CT_CELL_MASK) - + ((dy_flags & DY_UHEX) ? 4 : 2); - g_chartab[c] &= ~CT_PRINT_CHAR; - } - else - { - g_chartab[c] = (g_chartab[c] & ~CT_CELL_MASK) - + 1; - g_chartab[c] |= CT_PRINT_CHAR; - } + g_chartab[c] = (g_chartab[c] & ~CT_CELL_MASK) + + ((dy_flags & DY_UHEX) ? 4 : 2); + g_chartab[c] &= ~CT_PRINT_CHAR; } - } - else if (i == 2) // (re)set fname flag - { - if (tilde) - g_chartab[c] &= ~CT_FNAME_CHAR; - else - g_chartab[c] |= CT_FNAME_CHAR; - } - else // i == 3 (re)set keyword flag - { - if (tilde) - RESET_CHARTAB(buf, c); else - SET_CHARTAB(buf, c); + { + g_chartab[c] = (g_chartab[c] & ~CT_CELL_MASK) + 1; + g_chartab[c] |= CT_PRINT_CHAR; + } } } - ++c; + else if (var == p_isf) // (re)set fname flag + { + if (tilde) + g_chartab[c] &= ~CT_FNAME_CHAR; + else + g_chartab[c] |= CT_FNAME_CHAR; + } + else // var == p_isk || var == buf->b_p_isk + // (re)set keyword flag + { + if (tilde) + RESET_CHARTAB(buf, c); + else + SET_CHARTAB(buf, c); + } } - - c = *p; - p = skip_to_option_part(p); - if (c == ',' && *p == NUL) - // Trailing comma is not allowed. - return FAIL; + ++c; } } - chartab_initialized = TRUE; + return OK; } diff --git a/src/cmdexpand.c b/src/cmdexpand.c index a7c07d658c..082ec07be9 100644 --- a/src/cmdexpand.c +++ b/src/cmdexpand.c @@ -2828,7 +2828,7 @@ expand_files_and_dirs( { int free_pat = FALSE; int i; - int ret; + int ret = FAIL; // for ":set path=" and ":set tags=" halve backslashes for escaped // space @@ -2859,19 +2859,28 @@ expand_files_and_dirs( } } - if (xp->xp_context == EXPAND_FILES) - flags |= EW_FILE; - else if (xp->xp_context == EXPAND_FILES_IN_PATH) - flags |= (EW_FILE | EW_PATH); - else if (xp->xp_context == EXPAND_DIRS_IN_CDPATH) - flags = (flags | EW_DIR | EW_CDPATH) & ~EW_FILE; + if (xp->xp_context == EXPAND_FILES_IN_PATH && *get_findexpr() != NUL) + { +#ifdef FEAT_EVAL + ret = expand_findexpr(pat, matches, numMatches); +#endif + } else - flags = (flags | EW_DIR) & ~EW_FILE; - if (options & WILD_ICASE) - flags |= EW_ICASE; + { + if (xp->xp_context == EXPAND_FILES) + flags |= EW_FILE; + else if (xp->xp_context == EXPAND_FILES_IN_PATH) + flags |= (EW_FILE | EW_PATH); + else if (xp->xp_context == EXPAND_DIRS_IN_CDPATH) + flags = (flags | EW_DIR | EW_CDPATH) & ~EW_FILE; + else + flags = (flags | EW_DIR) & ~EW_FILE; + if (options & WILD_ICASE) + flags |= EW_ICASE; - // Expand wildcards, supporting %:h and the like. - ret = expand_wildcards_eval(&pat, numMatches, matches, flags); + // Expand wildcards, supporting %:h and the like. + ret = expand_wildcards_eval(&pat, numMatches, matches, flags); + } if (free_pat) vim_free(pat); #ifdef BACKSLASH_IN_FILENAME diff --git a/src/cmdhist.c b/src/cmdhist.c index 684c08e704..74089b20ef 100644 --- a/src/cmdhist.c +++ b/src/cmdhist.c @@ -125,8 +125,6 @@ init_history(void) { int newlen; // new length of history table histentry_T *temp; - int i; - int j; int type; // If size of history table changed, reallocate it @@ -159,11 +157,16 @@ init_history(void) if (hisidx[type] < 0) // there are no entries yet { + int i; + for (i = 0; i < newlen; ++i) clear_hist_entry(&temp[i]); } else if (newlen > hislen) // array becomes bigger { + int i; + int j; + for (i = 0; i <= hisidx[type]; ++i) temp[i] = history[type][i]; j = i; @@ -174,13 +177,19 @@ init_history(void) } else // array becomes smaller or 0 { + int i; + int j; + j = hisidx[type]; for (i = newlen - 1; ; --i) { if (i >= 0) // copy newest entries temp[i] = history[type][j]; else // remove older entries + { vim_free(history[type][j].hisstr); + history[type][j].hisstrlen = 0; + } if (--j < 0) j = hislen - 1; if (j == hisidx[type]) @@ -200,6 +209,7 @@ clear_hist_entry(histentry_T *hisptr) hisptr->hisnum = 0; hisptr->viminfo = FALSE; hisptr->hisstr = NULL; + hisptr->hisstrlen = 0; hisptr->time_set = 0; } @@ -218,6 +228,7 @@ in_history( int i; int last_i = -1; char_u *p; + size_t len; if (hisidx[type] < 0) return FALSE; @@ -232,7 +243,7 @@ in_history( p = history[type][i].hisstr; if (STRCMP(str, p) == 0 && !(writing && history[type][i].viminfo) - && (type != HIST_SEARCH || sep == p[STRLEN(p) + 1])) + && (type != HIST_SEARCH || sep == p[history[type][i].hisstrlen + 1])) { if (!move_to_front) return TRUE; @@ -247,6 +258,7 @@ in_history( return FALSE; str = history[type][i].hisstr; + len = history[type][i].hisstrlen; while (i != hisidx[type]) { if (++i >= hislen) @@ -257,6 +269,7 @@ in_history( history[type][i].hisnum = ++hisnum[type]; history[type][i].viminfo = FALSE; history[type][i].hisstr = str; + history[type][i].hisstrlen = len; history[type][i].time_set = vim_time(); return TRUE; } @@ -337,8 +350,13 @@ add_to_history( // Store the separator after the NUL of the string. hisptr->hisstr = vim_strnsave(new_entry, new_entrylen + 2); - if (hisptr->hisstr != NULL) + if (hisptr->hisstr == NULL) + hisptr->hisstrlen = 0; + else + { hisptr->hisstr[new_entrylen + 1] = sep; + hisptr->hisstrlen = new_entrylen; + } hisptr->hisnum = ++hisnum[histype]; hisptr->viminfo = FALSE; @@ -405,20 +423,6 @@ calc_hist_idx(int histype, int num) return -1; } -/* - * Get a history entry by its index. - * "histype" may be one of the HIST_ values. - */ - static char_u * -get_history_entry(int histype, int idx) -{ - idx = calc_hist_idx(histype, idx); - if (idx >= 0) - return history[histype][idx].hisstr; - else - return (char_u *)""; -} - /* * Clear all entries of a history. * "histype" may be one of the HIST_ values. @@ -517,6 +521,7 @@ del_history_idx(int histype, int idx) return FALSE; idx = hisidx[histype]; vim_free(history[histype][i].hisstr); + history[histype][i].hisstrlen = 0; // When deleting the last added search string in a mapping, reset // last_maptick, so that the last added search string isn't deleted again. @@ -576,7 +581,6 @@ f_histadd(typval_T *argvars UNUSED, typval_T *rettv) f_histdel(typval_T *argvars UNUSED, typval_T *rettv UNUSED) { int n; - char_u buf[NUMBUFLEN]; char_u *str; if (in_vim9script() @@ -595,9 +599,14 @@ f_histdel(typval_T *argvars UNUSED, typval_T *rettv UNUSED) n = del_history_idx(get_histtype(str), (int)tv_get_number(&argvars[1])); else + { + char_u buf[NUMBUFLEN]; + // string given: remove all matching entries n = del_history_entry(get_histtype(str), tv_get_string_buf(&argvars[1], buf)); + } + rettv->vval.v_number = n; } @@ -607,9 +616,7 @@ f_histdel(typval_T *argvars UNUSED, typval_T *rettv UNUSED) void f_histget(typval_T *argvars UNUSED, typval_T *rettv) { - int type; - int idx; - char_u *str; + char_u *str; if (in_vim9script() && (check_for_string_arg(argvars, 0) == FAIL @@ -621,13 +628,21 @@ f_histget(typval_T *argvars UNUSED, typval_T *rettv) rettv->vval.v_string = NULL; else { + int type; + int idx; + type = get_histtype(str); if (argvars[1].v_type == VAR_UNKNOWN) idx = get_history_idx(type); else idx = (int)tv_get_number_chk(&argvars[1], NULL); // -1 on type error - rettv->vval.v_string = vim_strsave(get_history_entry(type, idx)); + + idx = calc_hist_idx(type, idx); + if (idx < 0) + rettv->vval.v_string = vim_strnsave((char_u *)"", 0); + else + rettv->vval.v_string = vim_strnsave(history[type][idx].hisstr, history[type][idx].hisstrlen); } rettv->v_type = VAR_STRING; } @@ -647,10 +662,9 @@ f_histnr(typval_T *argvars UNUSED, typval_T *rettv) histname = tv_get_string_chk(&argvars[0]); i = histname == NULL ? HIST_CMD - 1 : get_histtype(histname); if (i >= HIST_CMD && i < HIST_COUNT) - i = get_history_idx(i); + rettv->vval.v_number = get_history_idx(i); else - i = -1; - rettv->vval.v_number = i; + rettv->vval.v_number = -1; } #endif // FEAT_EVAL @@ -662,17 +676,21 @@ f_histnr(typval_T *argvars UNUSED, typval_T *rettv) void remove_key_from_history(void) { + char_u *p_start; + char_u *p_end; char_u *p; int i; i = hisidx[HIST_CMD]; if (i < 0) return; - p = history[HIST_CMD][i].hisstr; - if (p == NULL) + p_start = history[HIST_CMD][i].hisstr; + if (p_start == NULL) return; - for ( ; *p; ++p) + p_end = p_start + history[HIST_CMD][i].hisstrlen; + for (p = p_start; *p; ++p) + { if (STRNCMP(p, "key", 3) == 0 && !SAFE_isalpha(p[3])) { p = vim_strchr(p + 3, '='); @@ -682,9 +700,14 @@ remove_key_from_history(void) for (i = 0; p[i] && !VIM_ISWHITE(p[i]); ++i) if (p[i] == '\\' && p[i + 1]) ++i; - STRMOVE(p, p + i); + + mch_memmove(p, p + i, (p_end - (p + i)) + 1); // +1 for the NUL + p_end -= i; // adjust p_end for shortened string --p; } + } + + history[HIST_CMD][i].hisstrlen = (size_t)(p_end - p_start); } #endif @@ -750,17 +773,16 @@ ex_history(exarg_T *eap) for (; !got_int && histype1 <= histype2; ++histype1) { - STRCPY(IObuff, "\n # "); - STRCAT(STRCAT(IObuff, history_names[histype1]), " history"); + vim_snprintf((char *)IObuff, IOSIZE, "\n # %s history", history_names[histype1]); msg_puts_title((char *)IObuff); idx = hisidx[histype1]; hist = history[histype1]; j = hisidx1; k = hisidx2; if (j < 0) - j = (-j > hislen) ? 0 : hist[(hislen+j+idx+1) % hislen].hisnum; + j = (-j > hislen) ? 0 : hist[(hislen + j + idx + 1) % hislen].hisnum; if (k < 0) - k = (-k > hislen) ? 0 : hist[(hislen+k+idx+1) % hislen].hisnum; + k = (-k > hislen) ? 0 : hist[(hislen + k + idx + 1) % hislen].hisnum; if (idx >= 0 && j <= k) for (i = idx + 1; !got_int; ++i) { @@ -770,14 +792,16 @@ ex_history(exarg_T *eap) && hist[i].hisnum >= j && hist[i].hisnum <= k && !message_filtered(hist[i].hisstr)) { + int len; + msg_putchar('\n'); - sprintf((char *)IObuff, "%c%6d ", i == idx ? '>' : ' ', - hist[i].hisnum); + len = vim_snprintf((char *)IObuff, IOSIZE, + "%c%6d ", i == idx ? '>' : ' ', hist[i].hisnum); if (vim_strsize(hist[i].hisstr) > (int)Columns - 10) - trunc_string(hist[i].hisstr, IObuff + STRLEN(IObuff), - (int)Columns - 10, IOSIZE - (int)STRLEN(IObuff)); + trunc_string(hist[i].hisstr, IObuff + len, + (int)Columns - 10, IOSIZE - (int)len); else - STRCAT(IObuff, hist[i].hisstr); + STRCPY(IObuff + len, hist[i].hisstr); msg_outtrans(IObuff); out_flush(); } diff --git a/src/edit.c b/src/edit.c index e1500bc941..3c98684fed 100644 --- a/src/edit.c +++ b/src/edit.c @@ -1634,7 +1634,8 @@ decodeModifyOtherKeys(int c) if (typebuf.tb_len >= 4 && (c == CSI || (c == ESC && *p == '['))) { idx = (*p == '['); - if (p[idx] == '2' && p[idx + 1] == '7' && p[idx + 2] == ';') + if (p[idx] == '2' && p[idx + 1] == '7' && p[idx + 2] == ';' && + kitty_protocol_state != KKPS_ENABLED) { form = 1; idx += 3; @@ -1649,9 +1650,10 @@ decodeModifyOtherKeys(int c) break; ++idx; } + int kitty_no_mods = argidx == 0 && kitty_protocol_state == KKPS_ENABLED; if (idx < typebuf.tb_len && p[idx] == (form == 1 ? '~' : 'u') - && argidx == 1) + && (argidx == 1 || kitty_no_mods)) { // Match, consume the code. typebuf.tb_off += idx + 1; @@ -1661,7 +1663,7 @@ decodeModifyOtherKeys(int c) typebuf_was_filled = FALSE; #endif - mod_mask = decode_modifiers(arg[!form]); + mod_mask = kitty_no_mods ? 0 : decode_modifiers(arg[!form]); c = merge_modifyOtherKeys(arg[form], &mod_mask); } } diff --git a/src/errors.h b/src/errors.h index 5cd1b0681f..6707fc78be 100644 --- a/src/errors.h +++ b/src/errors.h @@ -3657,3 +3657,5 @@ EXTERN char e_wrong_character_width_for_field_str[] INIT(= N_("E1512: Wrong character width for field \"%s\"")); EXTERN char e_winfixbuf_cannot_go_to_buffer[] INIT(= N_("E1513: Cannot switch buffer. 'winfixbuf' is enabled")); +EXTERN char e_invalid_return_type_from_findexpr[] + INIT(= N_("E1514: findexpr did not return a List type")); diff --git a/src/ex_cmds.c b/src/ex_cmds.c index b990de444b..462232f728 100644 --- a/src/ex_cmds.c +++ b/src/ex_cmds.c @@ -5192,10 +5192,10 @@ ex_global(exarg_T *eap) delim = *cmd; // get the delimiter ++cmd; // skip delimiter if there is one pat = cmd; // remember start of pattern - patlen = STRLEN(pat); cmd = skip_regexp_ex(cmd, delim, magic_isset(), &eap->arg, NULL, NULL); if (cmd[0] == delim) // end delimiter found *cmd++ = NUL; // replace it with a NUL + patlen = STRLEN(pat); } if (search_regcomp(pat, patlen, &used_pat, RE_BOTH, which_pat, SEARCH_HIS, diff --git a/src/ex_docmd.c b/src/ex_docmd.c index 08cecb1540..2af9925eea 100644 --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -6929,6 +6929,146 @@ ex_wrongmodifier(exarg_T *eap) eap->errmsg = ex_errmsg(e_invalid_command_str, eap->cmd); } +#if defined(FEAT_EVAL) || defined(PROTO) +/* + * Evaluate the 'findexpr' expression and return the result. When evaluating + * the expression, v:fname is set to the ":find" command argument. + */ + static list_T * +eval_findexpr(char_u *ptr) +{ + sctx_T saved_sctx = current_sctx; + char_u *findexpr; + char_u *arg; + typval_T tv; + list_T *retlist = NULL; + + findexpr = get_findexpr(); + + set_vim_var_string(VV_FNAME, ptr, -1); + current_sctx = curbuf->b_p_script_ctx[BV_FEXPR]; + + arg = skipwhite(findexpr); + + ++textlock; + + // Evaluate the expression. If the expression is "FuncName()" call the + // function directly. + if (eval0_simple_funccal(arg, &tv, NULL, &EVALARG_EVALUATE) == FAIL) + retlist = NULL; + else + { + if (tv.v_type == VAR_LIST) + retlist = list_copy(tv.vval.v_list, TRUE, TRUE, get_copyID()); + else + emsg(_(e_invalid_return_type_from_findexpr)); + clear_tv(&tv); + } + --textlock; + clear_evalarg(&EVALARG_EVALUATE, NULL); + + set_vim_var_string(VV_FNAME, NULL, 0); + current_sctx = saved_sctx; + + return retlist; +} + +/* + * Find file names matching "pat" using 'findexpr' and return it in "files". + * Used for expanding the :find, :sfind and :tabfind command argument. + * Returns OK on success and FAIL otherwise. + */ + int +expand_findexpr(char_u *pat, char_u ***files, int *numMatches) +{ + list_T *l; + int len; + char_u *regpat; + + *numMatches = 0; + *files = NULL; + + // File name expansion uses wildchars. But the 'findexpr' expression + // expects a regular expression argument. So convert wildchars in the + // argument to regular expression patterns. + regpat = file_pat_to_reg_pat(pat, NULL, NULL, FALSE); + if (regpat == NULL) + return FAIL; + + l = eval_findexpr(regpat); + + vim_free(regpat); + + if (l == NULL) + return FAIL; + + len = list_len(l); + if (len == 0) // empty List + return FAIL; + + *files = ALLOC_MULT(char_u *, len); + if (*files == NULL) + return FAIL; + + // Copy all the List items + listitem_T *li; + int idx = 0; + FOR_ALL_LIST_ITEMS(l, li) + { + if (li->li_tv.v_type == VAR_STRING) + { + (*files)[idx] = vim_strsave(li->li_tv.vval.v_string); + idx++; + } + } + + *numMatches = idx; + list_free(l); + + return OK; +} + +/* + * Use 'findexpr' to find file 'findarg'. The 'count' argument is used to find + * the n'th matching file. + */ + static char_u * +findexpr_find_file(char_u *findarg, int findarg_len, int count) +{ + list_T *fname_list; + char_u *ret_fname = NULL; + char_u cc; + int fname_count; + + cc = findarg[findarg_len]; + findarg[findarg_len] = NUL; + + fname_list = eval_findexpr(findarg); + fname_count = list_len(fname_list); + + if (fname_count == 0) + semsg(_(e_cant_find_file_str_in_path), findarg); + else + { + if (count > fname_count) + semsg(_(e_no_more_file_str_found_in_path), findarg); + else + { + listitem_T *li = list_find(fname_list, count - 1); + if (li != NULL && li->li_tv.v_type == VAR_STRING) + ret_fname = vim_strsave(li->li_tv.vval.v_string); + } + } + + if (fname_list != NULL) + list_free(fname_list); + + findarg[findarg_len] = cc; + + return ret_fname; +} +#endif + /* * :sview [+command] file split window with new file, read-only * :split [[+command] file] split window with current or new file @@ -6978,11 +7118,22 @@ ex_splitview(exarg_T *eap) { char_u *file_to_find = NULL; char *search_ctx = NULL; - fname = find_file_in_path(eap->arg, (int)STRLEN(eap->arg), - FNAME_MESS, TRUE, curbuf->b_ffname, - &file_to_find, &search_ctx); - vim_free(file_to_find); - vim_findfile_cleanup(search_ctx); + + if (*get_findexpr() != NUL) + { +#ifdef FEAT_EVAL + fname = findexpr_find_file(eap->arg, (int)STRLEN(eap->arg), + eap->addr_count > 0 ? eap->line2 : 1); +#endif + } + else + { + fname = find_file_in_path(eap->arg, (int)STRLEN(eap->arg), + FNAME_MESS, TRUE, curbuf->b_ffname, + &file_to_find, &search_ctx); + vim_free(file_to_find); + vim_findfile_cleanup(search_ctx); + } if (fname == NULL) goto theend; eap->arg = fname; @@ -7247,27 +7398,37 @@ ex_find(exarg_T *eap) if (!check_can_set_curbuf_forceit(eap->forceit)) return; - char_u *fname; + char_u *fname = NULL; int count; char_u *file_to_find = NULL; char *search_ctx = NULL; - fname = find_file_in_path(eap->arg, (int)STRLEN(eap->arg), FNAME_MESS, - TRUE, curbuf->b_ffname, &file_to_find, &search_ctx); - if (eap->addr_count > 0) + if (*get_findexpr() != NUL) { - // Repeat finding the file "count" times. This matters when it appears - // several times in the path. - count = eap->line2; - while (fname != NULL && --count > 0) +#ifdef FEAT_EVAL + fname = findexpr_find_file(eap->arg, (int)STRLEN(eap->arg), + eap->addr_count > 0 ? eap->line2 : 1); +#endif + } + else + { + fname = find_file_in_path(eap->arg, (int)STRLEN(eap->arg), FNAME_MESS, + TRUE, curbuf->b_ffname, &file_to_find, &search_ctx); + if (eap->addr_count > 0) { - vim_free(fname); - fname = find_file_in_path(NULL, 0, FNAME_MESS, - FALSE, curbuf->b_ffname, &file_to_find, &search_ctx); + // Repeat finding the file "count" times. This matters when it appears + // several times in the path. + count = eap->line2; + while (fname != NULL && --count > 0) + { + vim_free(fname); + fname = find_file_in_path(NULL, 0, FNAME_MESS, + FALSE, curbuf->b_ffname, &file_to_find, &search_ctx); + } } + VIM_CLEAR(file_to_find); + vim_findfile_cleanup(search_ctx); } - VIM_CLEAR(file_to_find); - vim_findfile_cleanup(search_ctx); if (fname == NULL) return; diff --git a/src/ex_getln.c b/src/ex_getln.c index f50d63a265..6e990e775b 100644 --- a/src/ex_getln.c +++ b/src/ex_getln.c @@ -1430,7 +1430,7 @@ cmdline_browse_history( else { p = get_histentry(histype)[hiscnt].hisstr; - plen = STRLEN(p); + plen = get_histentry(histype)[hiscnt].hisstrlen; } if (histype == HIST_SEARCH diff --git a/src/indent.c b/src/indent.c index 4ba31d2aa0..e7de005ae0 100644 --- a/src/indent.c +++ b/src/indent.c @@ -869,11 +869,15 @@ get_number_indent(linenr_T lnum) #if defined(FEAT_LINEBREAK) || defined(PROTO) /* + * Check "briopt" as 'breakindentopt' and update the members of "wp". * This is called when 'breakindentopt' is changed and when a window is * initialized. + * Returns FAIL for failure, OK otherwise. */ int -briopt_check(win_T *wp) +briopt_check( + char_u *briopt, // when NULL: use "wp->w_p_briopt" + win_T *wp) // when NULL: only check "briopt" { char_u *p; int bri_shift = 0; @@ -882,7 +886,11 @@ briopt_check(win_T *wp) int bri_list = 0; int bri_vcol = 0; - p = wp->w_p_briopt; + if (briopt != NULL) + p = briopt; + else + p = wp->w_p_briopt; + while (*p != NUL) { // Note: Keep this in sync with p_briopt_values @@ -918,6 +926,9 @@ briopt_check(win_T *wp) ++p; } + if (wp == NULL) + return OK; + wp->w_briopt_shift = bri_shift; wp->w_briopt_min = bri_min; wp->w_briopt_sbr = bri_sbr; diff --git a/src/main.c b/src/main.c index e3481eb812..e21a5b817f 100644 --- a/src/main.c +++ b/src/main.c @@ -1770,7 +1770,11 @@ getout(int exitval) } #ifdef FEAT_VIMINFO - if (*p_viminfo != NUL) + if ( +# ifdef EXITFREE + entered_free_all_mem == FALSE && +# endif + *p_viminfo != NUL) // Write out the registers, history, marks etc, to the viminfo file write_viminfo(NULL, FALSE); #endif diff --git a/src/option.c b/src/option.c index 86486a7f10..2fdbbdebd5 100644 --- a/src/option.c +++ b/src/option.c @@ -3487,6 +3487,16 @@ did_set_conceallevel(optset_T *args UNUSED) errmsg = e_invalid_argument; curwin->w_p_cole = 3; } + if (curwin->w_allbuf_opt.wo_cole < 0) + { + errmsg = e_argument_must_be_positive; + curwin->w_allbuf_opt.wo_cole = 0; + } + else if (curwin->w_allbuf_opt.wo_cole > 3) + { + errmsg = e_invalid_argument; + curwin->w_allbuf_opt.wo_cole = 3; + } return errmsg; } @@ -3552,6 +3562,16 @@ did_set_foldcolumn(optset_T *args UNUSED) errmsg = e_invalid_argument; curwin->w_p_fdc = 12; } + if (curwin->w_allbuf_opt.wo_fdc < 0) + { + errmsg = e_argument_must_be_positive; + curwin->w_allbuf_opt.wo_fdc = 0; + } + else if (curwin->w_allbuf_opt.wo_fdc > 12) + { + errmsg = e_invalid_argument; + curwin->w_allbuf_opt.wo_fdc = 12; + } return errmsg; } @@ -3881,11 +3901,21 @@ did_set_numberwidth(optset_T *args UNUSED) errmsg = e_argument_must_be_positive; curwin->w_p_nuw = 1; } - if (curwin->w_p_nuw > 20) + else if (curwin->w_p_nuw > 20) { errmsg = e_invalid_argument; curwin->w_p_nuw = 20; } + if (curwin->w_allbuf_opt.wo_nuw < 1) + { + errmsg = e_argument_must_be_positive; + curwin->w_allbuf_opt.wo_nuw = 1; + } + else if (curwin->w_allbuf_opt.wo_nuw > 20) + { + errmsg = e_invalid_argument; + curwin->w_allbuf_opt.wo_nuw = 20; + } curwin->w_nrwidth_line_count = 0; // trigger a redraw return errmsg; @@ -4166,6 +4196,27 @@ did_set_shiftwidth_tabstop(optset_T *args) long *pp = (long *)args->os_varp; char *errmsg = NULL; + if (curbuf->b_p_ts <= 0) + { + errmsg = e_argument_must_be_positive; + curbuf->b_p_ts = 8; + } + else if (curbuf->b_p_ts > TABSTOP_MAX) + { + errmsg = e_invalid_argument; + curbuf->b_p_ts = 8; + } + if (p_ts <= 0) + { + errmsg = e_argument_must_be_positive; + p_ts = 8; + } + else if (p_ts > TABSTOP_MAX) + { + errmsg = e_invalid_argument; + p_ts = 8; + } + if (curbuf->b_p_sw < 0) { errmsg = e_argument_must_be_positive; @@ -4176,6 +4227,18 @@ did_set_shiftwidth_tabstop(optset_T *args) : curbuf->b_p_ts; #else curbuf->b_p_sw = curbuf->b_p_ts; +#endif + } + if (p_sw < 0) + { + errmsg = e_argument_must_be_positive; +#ifdef FEAT_VARTABS + // Use the first 'vartabstop' value, or 'tabstop' if vts isn't in use. + p_sw = tabstop_count(curbuf->b_p_vts_array) > 0 + ? tabstop_first(curbuf->b_p_vts_array) + : curbuf->b_p_ts; +#else + p_sw = curbuf->b_p_ts; #endif } @@ -4284,6 +4347,26 @@ did_set_termguicolors(optset_T *args UNUSED) } #endif +#if defined(FEAT_TERMINAL) || defined(PROTO) +/* + * Process the updated 'termwinscroll' option value. + */ + char * +did_set_termwinscroll(optset_T *args) +{ + long *pp = (long *)args->os_varp; + char *errmsg = NULL; + + if (*pp < 1) + { + errmsg = e_argument_must_be_positive; + *pp = 1; + } + + return errmsg; +} +#endif + /* * Process the updated 'terse' option value. */ @@ -4347,13 +4430,18 @@ did_set_textwidth(optset_T *args UNUSED) errmsg = e_argument_must_be_positive; curbuf->b_p_tw = 0; } + if (p_tw < 0) + { + errmsg = e_argument_must_be_positive; + p_tw = 0; + } #ifdef FEAT_SYN_HL { win_T *wp; tabpage_T *tp; FOR_ALL_TAB_WINDOWS(tp, wp) - check_colorcolumn(wp); + check_colorcolumn(NULL, wp); } #endif @@ -4944,16 +5032,6 @@ check_num_option_bounds( p_window = Rows - 1; } - if (curbuf->b_p_ts <= 0) - { - errmsg = e_argument_must_be_positive; - curbuf->b_p_ts = 8; - } - else if (curbuf->b_p_ts > TABSTOP_MAX) - { - errmsg = e_invalid_argument; - curbuf->b_p_ts = 8; - } if (p_tm < 0) { errmsg = e_argument_must_be_positive; @@ -5086,6 +5164,10 @@ set_num_option( need_mouse_correct = TRUE; #endif + // May set global value for local option. + if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0) + *(long *)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL) = value; + // Invoke the option specific callback function to validate and apply the // new value. if (options[opt_idx].opt_did_set_cb != NULL) @@ -5105,10 +5187,6 @@ set_num_option( errmsg = check_num_option_bounds(pp, old_value, old_Rows, old_Columns, errbuf, errbuflen, errmsg); - // May set global value for local option. - if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0) - *(long *)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL) = *pp; - options[opt_idx].flags |= P_WAS_SET; #if defined(FEAT_EVAL) @@ -6447,6 +6525,11 @@ unset_global_local_option(char_u *name, void *from) case PV_FP: clear_string_option(&buf->b_p_fp); break; +# ifdef FEAT_EVAL + case PV_FEXPR: + clear_string_option(&buf->b_p_fexpr); + break; +# endif # ifdef FEAT_QUICKFIX case PV_EFM: clear_string_option(&buf->b_p_efm); @@ -6525,6 +6608,9 @@ get_varp_scope(struct vimoption *p, int scope) switch ((int)p->indir) { case PV_FP: return (char_u *)&(curbuf->b_p_fp); +#ifdef FEAT_EVAL + case PV_FEXPR: return (char_u *)&(curbuf->b_p_fexpr); +#endif #ifdef FEAT_QUICKFIX case PV_EFM: return (char_u *)&(curbuf->b_p_efm); case PV_GP: return (char_u *)&(curbuf->b_p_gp); @@ -6635,6 +6721,10 @@ get_varp(struct vimoption *p) #endif case PV_FP: return *curbuf->b_p_fp != NUL ? (char_u *)&(curbuf->b_p_fp) : p->var; +#ifdef FEAT_EVAL + case PV_FEXPR: return *curbuf->b_p_fexpr != NUL + ? (char_u *)&curbuf->b_p_fexpr : p->var; +#endif #ifdef FEAT_QUICKFIX case PV_EFM: return *curbuf->b_p_efm != NUL ? (char_u *)&(curbuf->b_p_efm) : p->var; @@ -6884,6 +6974,21 @@ get_equalprg(void) return curbuf->b_p_ep; } +/* + * Get the value of 'findexpr', either the buffer-local one or the global one. + */ + char_u * +get_findexpr(void) +{ +#ifdef FEAT_EVAL + if (*curbuf->b_p_fexpr == NUL) + return p_fexpr; + return curbuf->b_p_fexpr; +#else + return (char_u *)""; +#endif +} + /* * Copy options from one window to another. * Used when splitting a window. @@ -6908,11 +7013,11 @@ after_copy_winopt(win_T *wp) else wp->w_skipcol = 0; #ifdef FEAT_LINEBREAK - briopt_check(wp); + briopt_check(NULL, wp); #endif #ifdef FEAT_SYN_HL fill_culopt_flags(NULL, wp); - check_colorcolumn(wp); + check_colorcolumn(NULL, wp); #endif set_listchars_option(wp, wp->w_p_lcs, TRUE, NULL, 0); set_fillchars_option(wp, wp->w_p_fcs, TRUE, NULL, 0); @@ -7415,6 +7520,10 @@ buf_copy_options(buf_T *buf, int flags) buf->b_p_efm = empty_option; #endif buf->b_p_ep = empty_option; +#if defined(FEAT_EVAL) + buf->b_p_fexpr = vim_strsave(p_fexpr); + COPY_OPT_SCTX(buf, BV_FEXPR); +#endif buf->b_p_kp = empty_option; buf->b_p_path = empty_option; buf->b_p_tags = empty_option; diff --git a/src/option.h b/src/option.h index d4cebf95cb..b3ed525257 100644 --- a/src/option.h +++ b/src/option.h @@ -596,6 +596,9 @@ EXTERN char_u *p_ffs; // 'fileformats' EXTERN int p_fic; // 'fileignorecase' EXTERN char_u *p_ft; // 'filetype' EXTERN char_u *p_fcs; // 'fillchar' +#ifdef FEAT_EVAL +EXTERN char_u *p_fexpr; // 'findexpr' +#endif EXTERN int p_fixeol; // 'fixendofline' #ifdef FEAT_FOLDING EXTERN char_u *p_fcl; // 'foldclose' @@ -1194,6 +1197,7 @@ enum , BV_EP , BV_ET , BV_FENC + , BV_FEXPR , BV_FP #ifdef FEAT_EVAL , BV_BEXPR diff --git a/src/optiondefs.h b/src/optiondefs.h index c2c9cd4fc4..fa4e6a8eca 100644 --- a/src/optiondefs.h +++ b/src/optiondefs.h @@ -74,6 +74,7 @@ #define PV_FP OPT_BOTH(OPT_BUF(BV_FP)) #ifdef FEAT_EVAL # define PV_FEX OPT_BUF(BV_FEX) +# define PV_FEXPR OPT_BOTH(OPT_BUF(BV_FEXPR)) #endif #define PV_FF OPT_BUF(BV_FF) #define PV_FLP OPT_BUF(BV_FLP) @@ -1013,6 +1014,15 @@ static struct vimoption options[] = {(char_u *)"vert:|,fold:-,eob:~,lastline:@", (char_u *)0L} SCTX_INIT}, + {"findexpr", "fexpr", P_STRING|P_ALLOCED|P_VI_DEF|P_VIM|P_SECURE, +#if defined(FEAT_EVAL) + (char_u *)&p_fexpr, PV_FEXPR, did_set_optexpr, NULL, + {(char_u *)"", (char_u *)0L} +#else + (char_u *)NULL, PV_NONE, NULL, NULL, + {(char_u *)0L, (char_u *)0L} +#endif + SCTX_INIT}, {"fixendofline", "fixeol", P_BOOL|P_VI_DEF|P_RSTAT, (char_u *)&p_fixeol, PV_FIXEOL, did_set_eof_eol_fixeol_bomb, NULL, @@ -1539,7 +1549,7 @@ static struct vimoption options[] = #endif (char_u *)0L} SCTX_INIT}, {"iskeyword", "isk", P_STRING|P_ALLOCED|P_VIM|P_COMMA|P_NODUP, - (char_u *)&p_isk, PV_ISK, did_set_isopt, NULL, + (char_u *)&p_isk, PV_ISK, did_set_iskeyword, NULL, { (char_u *)"@,48-57,_", #if defined(MSWIN) @@ -2673,7 +2683,7 @@ static struct vimoption options[] = SCTX_INIT}, {"termwinscroll", "twsl", P_NUM|P_VI_DEF|P_VIM|P_RBUF, #ifdef FEAT_TERMINAL - (char_u *)&p_twsl, PV_TWSL, NULL, NULL, + (char_u *)&p_twsl, PV_TWSL, did_set_termwinscroll, NULL, {(char_u *)10000L, (char_u *)10000L} #else (char_u *)NULL, PV_NONE, NULL, NULL, diff --git a/src/optionstr.c b/src/optionstr.c index 79fff413c0..e88539697f 100644 --- a/src/optionstr.c +++ b/src/optionstr.c @@ -324,6 +324,9 @@ check_buf_options(buf_T *buf) check_string_option(&buf->b_p_efm); #endif check_string_option(&buf->b_p_ep); +#ifdef FEAT_EVAL + check_string_option(&buf->b_p_fexpr); +#endif check_string_option(&buf->b_p_path); check_string_option(&buf->b_p_tags); check_string_option(&buf->b_p_tc); @@ -1241,17 +1244,19 @@ did_set_breakat(optset_T *args UNUSED) * The 'breakindentopt' option is changed. */ char * -did_set_breakindentopt(optset_T *args UNUSED) +did_set_breakindentopt(optset_T *args) { - char *errmsg = NULL; + char_u **varp = (char_u **)args->os_varp; + + if (briopt_check(*varp, varp == &curwin->w_p_briopt ? curwin : NULL) + == FAIL) + return e_invalid_argument; - if (briopt_check(curwin) == FAIL) - errmsg = e_invalid_argument; // list setting requires a redraw - if (curwin->w_briopt_list) + if (varp == &curwin->w_p_briopt && curwin->w_briopt_list) redraw_all_later(UPD_NOT_VALID); - return errmsg; + return NULL; } int @@ -1484,9 +1489,11 @@ did_set_cinoptions(optset_T *args UNUSED) * The 'colorcolumn' option is changed. */ char * -did_set_colorcolumn(optset_T *args UNUSED) +did_set_colorcolumn(optset_T *args) { - return check_colorcolumn(curwin); + char_u **varp = (char_u **)args->os_varp; + + return check_colorcolumn(*varp, varp == &curwin->w_p_cc ? curwin : NULL); } #endif @@ -2346,8 +2353,7 @@ did_set_foldmethod(optset_T *args) { char_u **varp = (char_u **)args->os_varp; - if (check_opt_strings(*varp, p_fdm_values, FALSE) != OK - || *curwin->w_p_fdm == NUL) + if (check_opt_strings(*varp, p_fdm_values, FALSE) != OK || **varp == NUL) return e_invalid_argument; foldUpdateAll(curwin); @@ -2785,6 +2791,25 @@ did_set_imactivatekey(optset_T *args UNUSED) } #endif +/* + * The 'iskeyword' option is changed. + */ + char * +did_set_iskeyword(optset_T *args) +{ + char_u **varp = (char_u **)args->os_varp; + + if (varp == &p_isk) // only check for global-value + { + if (check_isopt(*varp) == FAIL) + return e_invalid_argument; + } + else // fallthrough for local-value + return did_set_isopt(args); + + return NULL; +} + /* * The 'isident' or the 'iskeyword' or the 'isprint' or the 'isfname' option is * changed. @@ -2792,7 +2817,7 @@ did_set_imactivatekey(optset_T *args UNUSED) char * did_set_isopt(optset_T *args) { - // 'isident', 'iskeyword', 'isprint or 'isfname' option: refill g_chartab[] + // 'isident', 'iskeyword', 'isprint' or 'isfname' option: refill g_chartab[] // If the new option is invalid, use old value. // 'lisp' option: refill g_chartab[] for '-' char. if (init_chartab() == FAIL) @@ -3120,8 +3145,8 @@ expand_set_nrformats(optexpand_T *args, int *numMatches, char_u ***matches) #if defined(FEAT_EVAL) || defined(PROTO) /* * One of the '*expr' options is changed: 'balloonexpr', 'diffexpr', - * 'foldexpr', 'foldtext', 'formatexpr', 'includeexpr', 'indentexpr', - * 'patchexpr', 'printexpr' and 'charconvert'. + * 'findexpr', 'foldexpr', 'foldtext', 'formatexpr', 'includeexpr', + * 'indentexpr', 'patchexpr', 'printexpr' and 'charconvert'. * */ char * @@ -3902,9 +3927,11 @@ did_set_term_option(optset_T *args) * The 'termwinkey' option is changed. */ char * -did_set_termwinkey(optset_T *args UNUSED) +did_set_termwinkey(optset_T *args) { - if (*curwin->w_p_twk != NUL && string_to_key(curwin->w_p_twk, TRUE) == 0) + char_u **varp = (char_u **)args->os_varp; + + if ((*varp)[0] != NUL && string_to_key(*varp, TRUE) == 0) return e_invalid_argument; return NULL; @@ -3914,17 +3941,16 @@ did_set_termwinkey(optset_T *args UNUSED) * The 'termwinsize' option is changed. */ char * -did_set_termwinsize(optset_T *args UNUSED) +did_set_termwinsize(optset_T *args) { + char_u **varp = (char_u **)args->os_varp; char_u *p; - if (*curwin->w_p_tws == NUL) + if ((*varp)[0] == NUL) return NULL; - p = skipdigits(curwin->w_p_tws); - if (p == curwin->w_p_tws - || (*p != 'x' && *p != '*') - || *skipdigits(p + 1) != NUL) + p = skipdigits(*varp); + if (p == *varp || (*p != 'x' && *p != '*') || *skipdigits(p + 1) != NUL) return e_invalid_argument; return NULL; diff --git a/src/proto/charset.pro b/src/proto/charset.pro index 2f64077834..54af280e94 100644 --- a/src/proto/charset.pro +++ b/src/proto/charset.pro @@ -1,6 +1,7 @@ /* charset.c */ int init_chartab(void); int buf_init_chartab(buf_T *buf, int global); +int check_isopt(char_u *isopt); void trans_characters(char_u *buf, int bufsize); char_u *transstr(char_u *s); char_u *str_foldcase(char_u *str, int orglen, char_u *buf, int buflen); diff --git a/src/proto/ex_docmd.pro b/src/proto/ex_docmd.pro index 2b86b1a7e5..053e35cbb8 100644 --- a/src/proto/ex_docmd.pro +++ b/src/proto/ex_docmd.pro @@ -47,6 +47,7 @@ void ex_stop(exarg_T *eap); void handle_drop(int filec, char_u **filev, int split, void (*callback)(void *), void *cookie); void handle_any_postponed_drop(void); void ex_edit(exarg_T *eap); +int expand_findexpr(char_u *pat, char_u ***files, int *numMatches); void ex_splitview(exarg_T *eap); void tabpage_new(void); void do_exedit(exarg_T *eap, win_T *old_curwin); diff --git a/src/proto/indent.pro b/src/proto/indent.pro index 6e56a0e370..f187ec5fc1 100644 --- a/src/proto/indent.pro +++ b/src/proto/indent.pro @@ -18,7 +18,7 @@ int get_indent_str(char_u *ptr, int ts, int no_ts); int get_indent_str_vtab(char_u *ptr, int ts, int *vts, int no_ts); int set_indent(int size, int flags); int get_number_indent(linenr_T lnum); -int briopt_check(win_T *wp); +int briopt_check(char_u *briopt, win_T *wp); int get_breakindent_win(win_T *wp, char_u *line); int inindent(int extra); void op_reindent(oparg_T *oap, int (*how)(void)); diff --git a/src/proto/option.pro b/src/proto/option.pro index 6d03886c44..59e0beb72c 100644 --- a/src/proto/option.pro +++ b/src/proto/option.pro @@ -71,6 +71,7 @@ char *did_set_spell(optset_T *args); char *did_set_swapfile(optset_T *args); char *did_set_tabclose(optset_T *args); char *did_set_termguicolors(optset_T *args); +char *did_set_termwinscroll(optset_T *args); char *did_set_terse(optset_T *args); char *did_set_textauto(optset_T *args); char *did_set_textmode(optset_T *args); @@ -129,6 +130,7 @@ char_u *get_option_var(int opt_idx); char_u *get_option_fullname(int opt_idx); opt_did_set_cb_T get_option_did_set_cb(int opt_idx); char_u *get_equalprg(void); +char_u *get_findexpr(void); void win_copy_options(win_T *wp_from, win_T *wp_to); void after_copy_winopt(win_T *wp); void copy_winopt(winopt_T *from, winopt_T *to); diff --git a/src/proto/optionstr.pro b/src/proto/optionstr.pro index 513092ada7..552b51e560 100644 --- a/src/proto/optionstr.pro +++ b/src/proto/optionstr.pro @@ -99,6 +99,7 @@ char *did_set_highlight(optset_T *args); int expand_set_highlight(optexpand_T *args, int *numMatches, char_u ***matches); char *did_set_iconstring(optset_T *args); char *did_set_imactivatekey(optset_T *args); +char *did_set_iskeyword(optset_T *args); char *did_set_isopt(optset_T *args); char *did_set_jumpoptions(optset_T *args); int expand_set_jumpoptions(optexpand_T *args, int *numMatches, char_u ***matches); diff --git a/src/proto/window.pro b/src/proto/window.pro index 441070ebfc..4ab7103101 100644 --- a/src/proto/window.pro +++ b/src/proto/window.pro @@ -98,7 +98,7 @@ void restore_snapshot(int idx, int close_curwin); int win_hasvertsplit(void); int get_win_number(win_T *wp, win_T *first_win); int get_tab_number(tabpage_T *tp); -char *check_colorcolumn(win_T *wp); +char *check_colorcolumn(char_u *cc, win_T *wp); int get_last_winid(void); int win_locked(win_T *wp); /* vim: set ft=c : */ diff --git a/src/structs.h b/src/structs.h index bb97265c02..bd6716ce21 100644 --- a/src/structs.h +++ b/src/structs.h @@ -1283,6 +1283,7 @@ typedef struct hist_entry int hisnum; // identifying number int viminfo; // when TRUE hisstr comes from viminfo char_u *hisstr; // actual entry, separator char after the NUL + size_t hisstrlen; // length of hisstr (excluding the NUL) time_t time_set; // when it was typed, zero if unknown } histentry_T; @@ -3329,6 +3330,9 @@ struct file_buffer char_u *b_p_efm; // 'errorformat' local value #endif char_u *b_p_ep; // 'equalprg' local value +#ifdef FEAT_EVAL + char_u *b_p_fexpr; // 'findexpr' local value +#endif char_u *b_p_path; // 'path' local value int b_p_ar; // 'autoread' local value char_u *b_p_tags; // 'tags' local value diff --git a/src/terminal.c b/src/terminal.c index 185df40b33..f644fb5e97 100644 --- a/src/terminal.c +++ b/src/terminal.c @@ -3441,7 +3441,8 @@ limit_scrollback(term_T *term, garray_T *gap, int update_buffer) if (gap->ga_len < term->tl_buffer->b_p_twsl) return; - int todo = term->tl_buffer->b_p_twsl / 10; + int todo = MAX(term->tl_buffer->b_p_twsl / 10, + gap->ga_len - term->tl_buffer->b_p_twsl); int i; curbuf = term->tl_buffer; diff --git a/src/testdir/Make_all.mak b/src/testdir/Make_all.mak index fbcb6adca4..22970868b3 100644 --- a/src/testdir/Make_all.mak +++ b/src/testdir/Make_all.mak @@ -233,6 +233,7 @@ NEW_TESTS = \ test_normal \ test_number \ test_options \ + test_options_all \ test_packadd \ test_partial \ test_paste \ @@ -494,6 +495,7 @@ NEW_TESTS_RES = \ test_normal.res \ test_number.res \ test_options.res \ + test_options_all.res \ test_packadd.res \ test_partial.res \ test_paste.res \ diff --git a/src/testdir/Make_ming.mak b/src/testdir/Make_ming.mak index f26950e2e3..2ffe4025e2 100644 --- a/src/testdir/Make_ming.mak +++ b/src/testdir/Make_ming.mak @@ -22,7 +22,7 @@ default: nongui include Make_all.mak # Explicit dependencies. -test_options.res test_alot.res: opt_test.vim +test_options_all.res: opt_test.vim TEST_OUTFILES = $(SCRIPTS_TINY_OUT) DOSTMP = dostmp @@ -157,8 +157,12 @@ test_gui_init.res: test_gui_init.vim $(VIMPROG) -u gui_preinit.vim -U gui_init.vim $(NO_PLUGINS) -S runtest.vim $< @$(DEL) vimcmd -opt_test.vim: ../optiondefs.h gen_opt_test.vim - $(VIMPROG) -e -s -u NONE $(COMMON_ARGS) --nofork -S gen_opt_test.vim ../optiondefs.h +opt_test.vim: gen_opt_test.vim ../optiondefs.h ../../runtime/doc/options.txt + $(VIMPROG) -e -s -u NONE $(COMMON_ARGS) --nofork -S $^ + @if test -f test.log; then \ + cat test.log; \ + exit 1; \ + fi test_bench_regexp.res: test_bench_regexp.vim -$(DEL) benchmark.out diff --git a/src/testdir/Make_mvc.mak b/src/testdir/Make_mvc.mak index bb38e25c51..1a54823e52 100644 --- a/src/testdir/Make_mvc.mak +++ b/src/testdir/Make_mvc.mak @@ -16,7 +16,7 @@ default: nongui !include Make_all.mak # Explicit dependencies. -test_options.res test_alot.res: opt_test.vim +test_options_all.res: opt_test.vim TEST_OUTFILES = $(SCRIPTS_TINY_OUT) DOSTMP = dostmp @@ -151,8 +151,9 @@ test_gui_init.res: test_gui_init.vim $(VIMPROG) -u gui_preinit.vim -U gui_init.vim $(NO_PLUGINS) -S runtest.vim $*.vim @del vimcmd -opt_test.vim: ../optiondefs.h gen_opt_test.vim - $(VIMPROG) -e -s -u NONE $(COMMON_ARGS) --nofork -S gen_opt_test.vim ../optiondefs.h +opt_test.vim: gen_opt_test.vim ../optiondefs.h ../../runtime/doc/options.txt + $(VIMPROG) -e -s -u NONE $(COMMON_ARGS) --nofork -S $** + @if exist test.log ( type test.log & exit /b 1 ) test_bench_regexp.res: test_bench_regexp.vim -if exist benchmark.out del benchmark.out diff --git a/src/testdir/Makefile b/src/testdir/Makefile index 2827f994a5..3b665e707f 100644 --- a/src/testdir/Makefile +++ b/src/testdir/Makefile @@ -30,7 +30,7 @@ default: nongui include Make_all.mak # Explicit dependencies. -test_options.res test_alot.res: opt_test.vim +test_options_all.res: opt_test.vim .SUFFIXES: .in .out .res .vim @@ -160,8 +160,14 @@ test_gui_init.res: test_gui_init.vim $(RUN_VIMTEST) -u gui_preinit.vim -U gui_init.vim $(NO_PLUGINS) -S runtest.vim $< @rm vimcmd -opt_test.vim: ../optiondefs.h gen_opt_test.vim - $(VIMPROG) -e -s -u NONE $(NO_INITS) --nofork --gui-dialog-file guidialog -S gen_opt_test.vim ../optiondefs.h +GEN_OPT_DEPS = gen_opt_test.vim ../optiondefs.h ../../runtime/doc/options.txt + +opt_test.vim: $(GEN_OPT_DEPS) + $(VIMPROG) -e -s -u NONE $(NO_INITS) --nofork --gui-dialog-file guidialog -S $(GEN_OPT_DEPS) + @if test -f test.log; then \ + cat test.log; \ + exit 1; \ + fi test_xxd.res: XXD=$(XXDPROG); export XXD; $(RUN_VIMTEST) $(NO_INITS) -S runtest.vim test_xxd.vim diff --git a/src/testdir/commondumps.vim b/src/testdir/commondumps.vim index cfe426cbde..1211ae9c4e 100644 --- a/src/testdir/commondumps.vim +++ b/src/testdir/commondumps.vim @@ -73,4 +73,4 @@ def g:Init(subtreedirname: string, count: number) endif enddef -# vim:fdm=syntax:sw=2:ts=8:noet:nolist:nosta: +# vim:fdm=syntax:sw=2:ts=8:noet:nosta: diff --git a/src/testdir/dos.vim b/src/testdir/dos.vim index 3ea6ab2a6d..6301af575a 100644 --- a/src/testdir/dos.vim +++ b/src/testdir/dos.vim @@ -3,7 +3,7 @@ set shell=c:\COMMAND.COM shellquote= shellxquote= shellcmdflag=/c shellredir=> " This is used only when the +eval feature is available. if executable("cmd.exe") - set shell=cmd.exe + set shell=cmd.exe shellcmdflag=/D\ /c endif source setup.vim diff --git a/src/testdir/gen_opt_test.vim b/src/testdir/gen_opt_test.vim index cc00ae8db1..795e195b13 100644 --- a/src/testdir/gen_opt_test.vim +++ b/src/testdir/gen_opt_test.vim @@ -1,6 +1,7 @@ -" Script to generate testdir/opt_test.vim from optiondefs.h +" Script to generate src/testdir/opt_test.vim from src/optiondefs.h and +" runtime/doc/options.txt -set cpo=&vim +set cpo&vim " Only do this when build with the +eval feature. if 1 @@ -11,109 +12,206 @@ set nomore const K_KENTER = -16715 -" The terminal size is restored at the end. -" Clear out t_WS, we don't want to resize the actual terminal. +" Get global-local options. +" "key" is full-name of the option. +" "value" is the local value to switch back to the global value. +b options.txt +call cursor(1, 1) +let global_locals = {} +while search("^'[^']*'.*\\n.*|global-local", 'W') + let fullname = getline('.')->matchstr("^'\\zs[^']*") + let global_locals[fullname] = '' +endwhile +call extend(global_locals, #{ + \ scrolloff: -1, + \ sidescrolloff: -1, + \ undolevels: -123456, + \}) + +" Get local-noglobal options. +" "key" is full-name of the option. +" "value" is no used. +b options.txt +call cursor(1, 1) +let local_noglobals = {} +while search("^'[^']*'.*\\n.*|local-noglobal", 'W') + let fullname = getline('.')->matchstr("^'\\zs[^']*") + let local_noglobals[fullname] = v:true +endwhile + +" Options to skip `setglobal` tests. +" "key" is full-name of the option. +" "value" is the reason. +let skip_setglobal_reasons = #{ + \ iminsert: 'The global value is always overwritten by the local value', + \ imsearch: 'The global value is always overwritten by the local value', + \} + +" Script header. +" The test values contains multibyte characters. let script = [ \ '" DO NOT EDIT: Generated with gen_opt_test.vim', - \ '" Used by test_options.vim.', + \ '" Used by test_options_all.vim.', \ '', - \ 'let save_columns = &columns', - \ 'let save_lines = &lines', - \ 'set t_WS=', + \ 'scriptencoding utf-8', \ ] -/#define p_term -let end = line('.') +b optiondefs.h +const end = search('#define p_term', 'nw') " font name that works everywhere (hopefully) let fontname = has('gui_macvim') ? '' : (has('win32') ? 'fixedsys' : 'fixed') " Two lists with values: values that work and values that fail. " When not listed, "othernum" or "otherstring" is used. +" When both lists are empty, skip tests for the option. +" For boolean options, if non-empty a fixed test will be run, otherwise skipped. let test_values = { + "\ boolean options + \ 'termguicolors': [ + \ has('vtp') && !has('vcon') && !has('gui_running') ? [] : [1], + \ []], + \ + "\ number options \ 'cmdheight': [[1, 2, 10], [-1, 0]], \ 'cmdwinheight': [[1, 2, 10], [-1, 0]], - \ 'columns': [[12, 80], [-1, 0, 10]], + \ 'columns': [[12, 80, 10000], [-1, 0, 10]], \ 'conceallevel': [[0, 1, 2, 3], [-1, 4, 99]], \ 'foldcolumn': [[0, 1, 4, 12], [-1, 13, 999]], \ 'helpheight': [[0, 10, 100], [-1]], - \ 'history': [[0, 1, 100], [-1, 10001]], - \ 'iminsert': [[0, 1], [-1, 3, 999]], - \ 'imsearch': [[-1, 0, 1], [-2, 3, 999]], + \ 'history': [[0, 1, 100, 10000], [-1, 10001]], + \ 'iminsert': [[0, 1, 2], [-1, 3, 999]], + \ 'imsearch': [[-1, 0, 1, 2], [-2, 3, 999]], \ 'imstyle': [[0, 1], [-1, 2, 999]], - \ 'lines': [[2, 24], [-1, 0, 1]], - \ 'linespace': [[0, 2, 4], ['']], + \ 'lines': [[2, 24, 1000], [-1, 0, 1]], + \ 'linespace': [[-1, 0, 2, 4, 999], ['']], \ 'numberwidth': [[1, 4, 8, 10, 11, 20], [-1, 0, 21]], \ 'regexpengine': [[0, 1, 2], [-1, 3, 999]], \ 'report': [[0, 1, 2, 9999], [-1]], - \ 'scroll': [[0, 1, 2, 20], [-1]], - \ 'scrolljump': [[-50, -1, 0, 1, 2, 20], [999]], - \ 'scrolloff': [[0, 1, 2, 20], [-1]], + \ 'scroll': [[0, 1, 2, 20], [-1, 999]], + \ 'scrolljump': [[-100, -1, 0, 1, 2, 20], [-101, 999]], + \ 'scrolloff': [[0, 1, 8, 999], [-1]], \ 'shiftwidth': [[0, 1, 8, 999], [-1]], \ 'sidescroll': [[0, 1, 8, 999], [-1]], \ 'sidescrolloff': [[0, 1, 8, 999], [-1]], - \ 'tabstop': [[1, 4, 8, 12], [-1, 0]], + \ 'tabstop': [[1, 4, 8, 12, 9999], [-1, 0, 10000]], + \ 'termwinscroll': [[1, 100, 99999], [-1, 0]], \ 'textwidth': [[0, 1, 8, 99], [-1]], \ 'timeoutlen': [[0, 8, 99999], [-1]], \ 'titlelen': [[0, 1, 8, 9999], [-1]], \ 'updatecount': [[0, 1, 8, 9999], [-1]], \ 'updatetime': [[0, 1, 8, 9999], [-1]], - \ 'verbose': [[-1, 0, 1, 8, 9999], []], + \ 'verbose': [[-1, 0, 1, 8, 9999], ['']], \ 'wildchar': [[-1, 0, 100, 'x', '^Y', '^@', '', '', '<', '^'], - \ ['', 'xxx', '', '', '', '', K_KENTER]], + \ ['', 'xxx', '', '', '', + \ '', '', K_KENTER]], \ 'wildcharm': [[-1, 0, 100, 'x', '^Y', '^@', '', '<', '^'], - \ ['', 'xxx', '', '', '', '', K_KENTER]], + \ ['', 'xxx', '', '', '', + \ '', '', K_KENTER]], \ 'winheight': [[1, 10, 999], [-1, 0]], \ 'winminheight': [[0, 1], [-1]], \ 'winminwidth': [[0, 1, 10], [-1]], \ 'winwidth': [[1, 10, 999], [-1, 0]], \ - \ 'ambiwidth': [['', 'single'], ['xxx']], + "\ string options + \ 'ambiwidth': [['', 'single', 'double'], ['xxx']], \ 'background': [['', 'light', 'dark'], ['xxx']], - \ 'backspace': [[0, 2, 3, '', 'eol', 'eol,start', 'indent,eol,nostop'], ['4', 'xxx']], - \ 'backupcopy': [['yes', 'auto'], ['', 'xxx', 'yes,no']], - \ 'backupext': [['xxx'], ['']], - \ 'belloff': [['', 'all', 'copy,error'], ['xxx']], - \ 'breakindentopt': [['', 'min:3', 'sbr'], ['xxx', 'min', 'min:x']], - \ 'browsedir': [['', 'last', '/'], ['xxx']], - \ 'bufhidden': [['', 'hide', 'wipe'], ['xxx', 'hide,wipe']], - \ 'buftype': [['', 'help', 'nofile'], ['xxx', 'help,nofile']], - \ 'casemap': [['', 'internal'], ['xxx']], + \ 'backspace': [[0, 1, 2, 3, '', 'indent', 'eol', 'start', 'nostop', + \ 'eol,start', 'indent,eol,nostop'], + \ [-1, 4, 'xxx']], + \ 'backupcopy': [['yes', 'no', 'auto'], ['', 'xxx', 'yes,no']], + \ 'backupext': [['xxx'], [&patchmode, '*']], + \ 'belloff': [['', 'all', 'backspace', 'cursor', 'complete', 'copy', + \ 'ctrlg', 'error', 'esc', 'ex', 'hangul', 'insertmode', 'lang', + \ 'mess', 'showmatch', 'operator', 'register', 'shell', 'spell', + \ 'term', 'wildmode', 'copy,error,shell'], + \ ['xxx']], + \ 'breakindentopt': [['', 'min:3', 'shift:4', 'shift:-2', 'sbr', 'list:5', + \ 'list:-1', 'column:10', 'column:-5', 'min:1,sbr,shift:2'], + \ ['xxx', 'min', 'min:x', 'min:-1', 'shift:x', 'sbr:1', 'list:x', + \ 'column:x']], + \ 'browsedir': [['', 'last', 'buffer', 'current', './Xdir\ with\ space'], + \ ['xxx']], + \ 'bufhidden': [['', 'hide', 'unload', 'delete', 'wipe'], + \ ['xxx', 'hide,wipe']], + \ 'buftype': [['', 'nofile', 'nowrite', 'acwrite', 'quickfix', 'help', + \ 'terminal', 'prompt', 'popup'], + \ ['xxx', 'help,nofile']], + \ 'casemap': [['', 'internal', 'keepascii', 'internal,keepascii'], + \ ['xxx']], \ 'cedit': [['', '^Y', '^@', '', ''], - \ ['xxx', 'f', '', '', '', ''], ['xxx']], - \ 'mkspellmem': [['10000,100,12'], ['', 'xxx']], - \ 'mouse': [['', 'a', 'nvi'], ['xxx', 'n,v,i']], - \ 'mousemodel': [['', 'popup'], ['xxx']], + \ 'mkspellmem': [['10000,100,12'], ['', 'xxx', '10000,100']], + \ 'mouse': [['', 'n', 'v', 'i', 'c', 'h', 'a', 'r', 'nvi'], + \ ['xxx', 'n,v,i']], + \ 'mousemodel': [['', 'extend', 'popup', 'popup_setpos'], ['xxx']], \ 'mouseshape': [['', 'n:arrow'], ['xxx']], - \ 'nrformats': [['', 'alpha', 'alpha,hex,bin'], ['xxx']], - \ 'previewpopup': [['', 'height:13', 'width:10,height:234'], ['height:yes', 'xxx', 'xxx:99']], - \ 'printmbfont': [['', 'r:some', 'b:Bold,c:yes'], ['xxx']], - \ 'printoptions': [['', 'header:0', 'left:10pc,top:5pc'], ['xxx']], - \ 'scrollopt': [['', 'ver', 'ver,hor'], ['xxx']], + \ 'nrformats': [['', 'alpha', 'octal', 'hex', 'bin', 'unsigned', 'blank', + \ 'alpha,hex,bin'], + \ ['xxx']], + \ 'patchmode': [['', 'xxx', '.x'], [&backupext, '*']], + \ 'previewpopup': [['', 'height:13', 'width:20', 'highlight:That', + \ 'align:item', 'align:menu', 'border:on', 'border:off', + \ 'width:10,height:234,highlight:Mine'], + \ ['xxx', 'xxx:99', 'height:yes', 'width:no', 'align:xxx', + \ 'border:maybe', 'border:1', 'border:']], + \ 'printmbfont': [['', 'r:some', 'b:some', 'i:some', 'o:some', 'c:yes', + \ 'c:no', 'a:yes', 'a:no', 'b:Bold,c:yes'], + \ ['xxx', 'xxx,c:yes', 'xxx:', 'xxx:,c:yes']], + \ 'printoptions': [['', 'header:0', 'left:10pc,top:5pc'], + \ ['xxx', 'header:-1']], + \ 'scrollopt': [['', 'ver', 'hor', 'jump', 'ver,hor'], ['xxx']], \ 'renderoptions': [[''], ['xxx']], \ 'rightleftcmd': [['search'], ['xxx']], - \ 'selection': [['old', 'inclusive'], ['', 'xxx']], - \ 'selectmode': [['', 'mouse', 'key,cmd'], ['xxx']], - \ 'sessionoptions': [['', 'blank', 'help,options,slash'], ['xxx']], - \ 'showcmdloc': [['last', 'statusline', 'tabline'], ['xxx']], - \ 'signcolumn': [['', 'auto', 'no'], ['xxx', 'no,yes']], + \ 'rulerformat': [['', 'xxx'], ['%-', '%(', '%15(%%']], + \ 'selection': [['old', 'inclusive', 'exclusive'], ['', 'xxx']], + \ 'selectmode': [['', 'mouse', 'key', 'cmd', 'key,cmd'], ['xxx']], + \ 'sessionoptions': [['', 'blank', 'curdir', 'sesdir', + \ 'help,options,slash'], + \ ['xxx', 'curdir,sesdir']], + \ 'showcmdloc': [['', 'last', 'statusline', 'tabline'], ['xxx']], + \ 'signcolumn': [['', 'auto', 'no', 'yes', 'number'], ['xxx', 'no,yes']], \ 'spellfile': [['', 'file.en.add', 'xxx.en.add,yyy.gb.add,zzz.ja.add', \ '/tmp/dir\ with\ space/en.utf-8.add', \ '/tmp/dir\\,with\\,comma/en.utf-8.add'], - \ ['xxx', '/tmp/file', ',file.en.add', 'xxx,yyy.en.add', - \ 'xxx.en.add,yyy,zzz.ja.add']], + \ ['xxx', '/tmp/file', '/tmp/dir*with:invalid?char/file.en.add', + \ ',file.en.add', 'xxx,yyy.en.add', 'xxx.en.add,yyy,zzz.ja.add']], \ 'spelllang': [['', 'xxx', 'sr@latin'], ['not&lang', "that\\\rthere"]], \ 'spelloptions': [['', 'camel'], ['xxx']], - \ 'spellsuggest': [['', 'best', 'double,33'], ['xxx']], - \ 'splitkeep': [['cursor', 'screen', 'topline'], ['xxx']], + \ 'spellsuggest': [['', 'best', 'double', 'fast', '100', 'timeout:100', + \ 'timeout:-1', 'file:/tmp/file', 'expr:Func()', 'double,33'], + \ ['xxx', '-1', 'timeout:', 'best,double', 'double,fast']], + \ 'splitkeep': [['', 'cursor', 'screen', 'topline'], ['xxx']], + \ 'statusline': [['', 'xxx'], ['%$', '%{', '%{%', '%{%}', '%(', '%)']], \ 'swapsync': [['', 'sync', 'fsync'], ['xxx']], - \ 'switchbuf': [['', 'useopen', 'split,newtab'], ['xxx']], - \ 'tabclose': [['', 'left', 'left,uselast'], ['xxx']], - \ 'tagcase': [['smart', 'match'], ['', 'xxx', 'smart,match']], - \ 'term': [[], []], - \ 'termguicolors': [[], []], + \ 'switchbuf': [['', 'useopen', 'usetab', 'split', 'vsplit', 'newtab', + \ 'uselast', 'split,newtab'], + \ ['xxx']], + \ 'tabclose': [['', 'left', 'uselast', 'left,uselast'], ['xxx']], + \ 'tabline': [['', 'xxx'], ['%$', '%{', '%{%', '%{%}', '%(', '%)']], + \ 'tagcase': [['followic', 'followscs', 'ignore', 'match', 'smart'], + \ ['', 'xxx', 'smart,match']], \ 'termencoding': [(has('gui_gtk') || has('gui_macvim')) ? [] : ['', 'utf-8'], ['xxx']], - \ 'termwinkey': [['', 'f', '^Y', '^@', '', '', "\u3042", '<', '^'], - \ ['', '', '', "\u3042", '<', + \ '^'], + \ ['', '', '', '~', '[', ']', 'b,s', + \ 'bs'], + \ ['xxx']], + \ 'wildmode': [['', 'full', 'longest', 'list', 'lastused', 'list:full', + \ 'full,longest', 'full,full,full,full'], + \ ['xxx', 'a4', 'full,full,full,full,full']], \ 'wildoptions': [['', 'tagfile', 'pum', 'fuzzy'], ['xxx']], - \ 'winaltkeys': [['menu', 'no'], ['', 'xxx']], + \ 'winaltkeys': [['no', 'yes', 'menu'], ['', 'xxx']], \ + "\ skipped options \ 'luadll': [[], []], \ 'perldll': [[], []], \ 'pythondll': [[], []], @@ -187,85 +322,164 @@ let test_values = { \ 'pyxversion': [[], []], \ 'rubydll': [[], []], \ 'tcldll': [[], []], + \ 'term': [[], []], + \ 'ttytype': [[], []], \ \ 'blurradius': [[], [-1]], \ 'fuoptions': [[], ['xxx']], \ 'transparency': [[], ['-1']], \ + "\ default behaviours \ 'othernum': [[-1, 0, 100], ['']], \ 'otherstring': [['', 'xxx'], []], \} +" Two lists with values: values that pre- and post-processing in test. +" Clear out t_WS: we don't want to resize the actual terminal. +let test_prepost = { + \ 'browsedir': [["call mkdir('Xdir with space', 'D')"], []], + \ 'columns': [[ + \ 'set t_WS=', + \ 'let save_columns = &columns' + \ ], [ + \ 'let &columns = save_columns', + \ 'set t_WS&' + \ ]], + \ 'lines': [[ + \ 'set t_WS=', + \ 'let save_lines = &lines' + \ ], [ + \ 'let &lines = save_lines', + \ 'set t_WS&' + \ ]], + \ 'verbosefile': [[], ['call delete("Xfile")']], + \} + +const invalid_options = test_values->keys() + \->filter({-> v:val !~# '^other' && !exists($"&{v:val}")}) +if !empty(invalid_options) + throw $"Invalid option name in test_values: '{invalid_options->join("', '")}'" +endif + 1 -/struct vimoption options +call search('struct vimoption options') while 1 - /{" - if line('.') > end + if search('{"', 'W') > end break endif let line = getline('.') - let name = substitute(line, '.*{"\([^"]*\)".*', '\1', '') + let fullname = substitute(line, '.*{"\([^"]*\)".*', '\1', '') let shortname = substitute(line, '.*"\([^"]*\)".*', '\1', '') - if has_key(test_values, name) - let a = test_values[name] - elseif line =~ 'P_NUM' - let a = test_values['othernum'] - else - let a = test_values['otherstring'] + let [valid_values, invalid_values] = test_values[ + \ has_key(test_values, fullname) ? fullname + \ : line =~ 'P_NUM' ? 'othernum' + \ : 'otherstring'] + + if empty(valid_values) && empty(invalid_values) + continue endif - if len(a[0]) > 0 || len(a[1]) > 0 - if line =~ 'P_BOOL' - if name != 'fullscreen' - call add(script, 'set ' . name) - call add(script, 'set ' . shortname) - call add(script, 'set no' . name) - call add(script, 'set no' . shortname) - endif - else - for val in a[0] - call add(script, 'set ' . name . '=' . val) - call add(script, 'set ' . shortname . '=' . val) - endfor - " setting an option can only fail when it's implemented. - call add(script, "if exists('+" . name . "')") - for val in a[1] - call add(script, "silent! call assert_fails('set " . name . "=" . val . "')") - call add(script, "silent! call assert_fails('set " . shortname . "=" . val . "')") + call add(script, $"func Test_opt_set_{fullname}()") + call add(script, $"if exists('+{fullname}') && execute('set!') =~# '\\n..{fullname}\\([=\\n]\\|$\\)'") + call add(script, $"let l:saved = [&g:{fullname}, &l:{fullname}]") + call add(script, 'endif') + + let [pre_processing, post_processing] = get(test_prepost, fullname, [[], []]) + let script += pre_processing + + if line =~ 'P_BOOL' + if fullname != 'fullscreen' " MacVim-specific. Don't test full screen as it is a little intrusive. + + for opt in [fullname, shortname] + for cmd in ['set', 'setlocal', 'setglobal'] + call add(script, $'{cmd} {opt}') + call add(script, $'{cmd} no{opt}') + call add(script, $'{cmd} inv{opt}') + call add(script, $'{cmd} {opt}!') endfor - call add(script, "endif") - endif + endfor - " cannot change 'termencoding' in GTK - if name != 'termencoding' || !(has('gui_gtk') || has('gui_macvim')) - call add(script, 'set ' . name . '&') - call add(script, 'set ' . shortname . '&') - endif - if name == 'verbosefile' - call add(script, 'call delete("xxx")') endif + else " P_NUM || P_STRING + " Normal tests + for opt in [fullname, shortname] + for cmd in ['set', 'setlocal', 'setglobal'] + for val in valid_values + if local_noglobals->has_key(fullname) && cmd ==# 'setglobal' + " Skip `:setglobal {option}={val}` for local-noglobal option. + " It has no effect. + let pre = '" Skip local-noglobal: ' + else + let pre = '' + endif + call add(script, $'{pre}{cmd} {opt}={val}') + endfor + endfor + " Testing to clear the local value and switch back to the global value. + if global_locals->has_key(fullname) + let switchback_val = global_locals[fullname] + call add(script, $'setlocal {opt}={switchback_val}') + call add(script, $'call assert_equal(&g:{fullname}, &{fullname})') + endif + endfor - if name == 'more' - call add(script, 'set nomore') - elseif name == 'lines' - call add(script, 'let &lines = save_lines') - endif + " Failure tests + " Setting an option can only fail when it's implemented. + call add(script, $"if exists('+{fullname}')") + for opt in [fullname, shortname] + for cmd in ['set', 'setlocal', 'setglobal'] + for val in invalid_values + if val is# global_locals->get(fullname, {}) && cmd ==# 'setlocal' + " Skip setlocal switchback-value to global-local option. It will + " not result in failure. + let pre = '" Skip global-local: ' + elseif local_noglobals->has_key(fullname) && cmd ==# 'setglobal' + " Skip setglobal to local-noglobal option. It will not result in + " failure. + let pre = '" Skip local-noglobal: ' + elseif skip_setglobal_reasons->has_key(fullname) && cmd ==# 'setglobal' + " Skip setglobal to reasoned option. It will not result in failure. + let reason = skip_setglobal_reasons[fullname] + let pre = $'" Skip {reason}: ' + else + let pre = '' + endif + let cmdline = $'{cmd} {opt}={val}' + call add(script, $"{pre}silent! call assert_fails({string(cmdline)})") + endfor + endfor + endfor + call add(script, "endif") endif -endwhile -call add(script, 'let &columns = save_columns') -call add(script, 'let &lines = save_lines') + " Cannot change 'termencoding' in GTK + if fullname != 'termencoding' || !(has('gui_gtk') || has('gui_macvim')) + call add(script, $'set {fullname}&') + call add(script, $'set {shortname}&') + call add(script, $"if exists('l:saved')") + call add(script, $"let [&g:{fullname}, &l:{fullname}] = l:saved") + call add(script, 'endif') + endif + + let script += post_processing + call add(script, 'endfunc') +endwhile call writefile(script, 'opt_test.vim') -" Exit with error-code if error occurs. +" Write error messages if error occurs. catch - set verbose=1 - echoc 'Error:' v:exception 'in' v:throwpoint - cq! 1 + " Append errors to test.log + let error = $'Error: {v:exception} in {v:throwpoint}' + echoc error + split test.log + call append('$', error) + write endtry endif qa! + +" vim:sw=2:ts=8:noet:nosta: diff --git a/src/testdir/shared.vim b/src/testdir/shared.vim index dd2f012c01..1edf65ac88 100644 --- a/src/testdir/shared.vim +++ b/src/testdir/shared.vim @@ -59,7 +59,7 @@ func RunCommand(cmd) let job = job_start(a:cmd, {"stoponexit": "hup"}) call job_setoptions(job, {"stoponexit": "kill"}) elseif has('win32') - exe 'silent !start cmd /c start "test_channel" ' . a:cmd + exe 'silent !start cmd /D /c start "test_channel" ' . a:cmd else exe 'silent !' . a:cmd . '&' endif diff --git a/src/testdir/term_util.vim b/src/testdir/term_util.vim index d376a95778..1a06db7eb1 100644 --- a/src/testdir/term_util.vim +++ b/src/testdir/term_util.vim @@ -174,7 +174,7 @@ endfunc " number. func Run_shell_in_terminal(options) if has('win32') - let buf = term_start([&shell, '/k'], a:options) + let buf = term_start([&shell, '/D', '/k'], a:options) else let buf = term_start(&shell, a:options) endif diff --git a/src/testdir/test_autocmd.vim b/src/testdir/test_autocmd.vim index f983c10f17..5d2c7334ef 100644 --- a/src/testdir/test_autocmd.vim +++ b/src/testdir/test_autocmd.vim @@ -89,7 +89,7 @@ if has('timers') let g:triggered = 0 au CursorHoldI * let g:triggered += 1 set updatetime=100 - call job_start(has('win32') ? 'cmd /c echo:' : 'echo', + call job_start(has('win32') ? 'cmd /D /c echo:' : 'echo', \ {'exit_cb': {-> timer_start(200, 'ExitInsertMode')}}) call feedkeys('a', 'x!') call assert_equal(1, g:triggered) diff --git a/src/testdir/test_channel.vim b/src/testdir/test_channel.vim index 4215a5874b..78c834d70d 100644 --- a/src/testdir/test_channel.vim +++ b/src/testdir/test_channel.vim @@ -1429,7 +1429,7 @@ func Test_exit_cb_wipes_buf() new let g:wipe_buf = bufnr('') - let job = job_start(has('win32') ? 'cmd /c echo:' : ['true'], + let job = job_start(has('win32') ? 'cmd /D /c echo:' : ['true'], \ {'exit_cb': 'ExitCbWipe'}) let timer = timer_start(300, {-> feedkeys("\", 'nt')}, {'repeat': 5}) call feedkeys(repeat('g', 1000) . 'o', 'ntx!') @@ -1770,7 +1770,7 @@ func Test_job_start_fails() call assert_fails("call job_start('ls', \ {'err_io' : 'buffer', 'err_buf' : -1})", 'E475:') - let cmd = has('win32') ? "cmd /c dir" : "ls" + let cmd = has('win32') ? "cmd /D /c dir" : "ls" set nomodifiable call assert_fails("call job_start(cmd, @@ -2308,7 +2308,7 @@ endfunc func Test_issue_5150() if has('win32') - let cmd = 'cmd /c pause' + let cmd = 'cmd /D /c pause' else let cmd = 'grep foo' endif @@ -2438,7 +2438,7 @@ func Test_cb_with_input() let g:wait_exit_cb = 1 if has('win32') - let cmd = 'cmd /c echo "Vim''s test"' + let cmd = 'cmd /D /c echo "Vim''s test"' else let cmd = 'echo "Vim''s test"' endif diff --git a/src/testdir/test_filetype.vim b/src/testdir/test_filetype.vim index a93b56317c..f81d18fe62 100644 --- a/src/testdir/test_filetype.vim +++ b/src/testdir/test_filetype.vim @@ -133,7 +133,8 @@ def s:GetFilenameChecks(): dict> bib: ['file.bib'], bicep: ['file.bicep', 'file.bicepparam'], bindzone: ['named.root', '/bind/db.file', '/named/db.file', 'any/bind/db.file', 'any/named/db.file', 'foobar.zone'], - bitbake: ['file.bb', 'file.bbappend', 'file.bbclass', 'build/conf/local.conf', 'meta/conf/layer.conf', 'build/conf/bbappend.conf', 'meta-layer/conf/distro/foo.conf'], + bitbake: ['file.bb', 'file.bbappend', 'file.bbclass', 'build/conf/local.conf', 'meta/conf/layer.conf', 'build/conf/bbappend.conf', 'meta-layer/conf/distro/foo.conf', + 'project-spec/configs/zynqmp-generic-xczu7ev.conf'], blade: ['file.blade.php'], blank: ['file.bl'], blueprint: ['file.blp'], @@ -673,7 +674,7 @@ def s:GetFilenameChecks(): dict> '/tmp/bash-fc-3Ozjlw', '/tmp/bash-fc.3Ozjlw', 'PKGBUILD', 'APKBUILD', 'file.bash', '/usr/share/doc/bash-completion/filter.sh', '/etc/udev/cdsymlinks.conf', 'any/etc/udev/cdsymlinks.conf', 'file.bats', '.ash_history', 'any/etc/neofetch/config.conf', '.xprofile', 'user-dirs.defaults', 'user-dirs.dirs', 'makepkg.conf', '.makepkg.conf', 'file.mdd', 'file.cygport', '.env', '.envrc', 'devscripts.conf', - '.devscripts'], + '.devscripts', 'file.lo', 'file.la', 'file.lai'], sieve: ['file.siv', 'file.sieve'], sil: ['file.sil'], simula: ['file.sim'], @@ -867,7 +868,10 @@ def s:GetFilenameChecks(): dict> xinetd: ['/etc/xinetd.conf', '/etc/xinetd.d/file', 'any/etc/xinetd.conf', 'any/etc/xinetd.d/file'], xkb: ['/usr/share/X11/xkb/compat/pc', '/usr/share/X11/xkb/geometry/pc', '/usr/share/X11/xkb/keycodes/evdev', '/usr/share/X11/xkb/symbols/pc', '/usr/share/X11/xkb/types/pc'], xmath: ['file.msc', 'file.msf'], - xml: ['/etc/blkid.tab', '/etc/blkid.tab.old', 'file.xmi', 'file.csproj', 'file.csproj.user', 'file.fsproj', 'file.fsproj.user', 'file.vbproj', 'file.vbproj.user', 'file.ui', 'file.tpm', '/etc/xdg/menus/file.menu', 'fglrxrc', 'file.xlf', 'file.xliff', 'file.xul', 'file.wsdl', 'file.wpl', 'any/etc/blkid.tab', 'any/etc/blkid.tab.old', 'any/etc/xdg/menus/file.menu', 'file.atom', 'file.rss', 'file.cdxml', 'file.psc1', 'file.mpd', 'fonts.conf', 'file.xcu', 'file.xlb', 'file.xlc', 'file.xba', 'file.xpr', 'file.xpfm', 'file.spfm', 'file.bxml'], + xml: ['/etc/blkid.tab', '/etc/blkid.tab.old', 'file.xmi', 'file.csproj', 'file.csproj.user', 'file.fsproj', 'file.fsproj.user', 'file.vbproj', 'file.vbproj.user', 'file.ui', + 'file.tpm', '/etc/xdg/menus/file.menu', 'fglrxrc', 'file.xlf', 'file.xliff', 'file.xul', 'file.wsdl', 'file.wpl', 'any/etc/blkid.tab', 'any/etc/blkid.tab.old', + 'any/etc/xdg/menus/file.menu', 'file.atom', 'file.rss', 'file.cdxml', 'file.psc1', 'file.mpd', 'fonts.conf', 'file.xcu', 'file.xlb', 'file.xlc', 'file.xba', 'file.xpr', + 'file.xpfm', 'file.spfm', 'file.bxml', 'file.mmi'], xmodmap: ['anyXmodmap', 'Xmodmap', 'some-Xmodmap', 'some-xmodmap', 'some-xmodmap-file', 'xmodmap', 'xmodmap-file'], xpm: ['file.xpm'], xpm2: ['file.xpm2'], diff --git a/src/testdir/test_findfile.vim b/src/testdir/test_findfile.vim index a5e18b9570..3a1066bf31 100644 --- a/src/testdir/test_findfile.vim +++ b/src/testdir/test_findfile.vim @@ -1,5 +1,7 @@ " Test findfile() and finddir() +source check.vim + let s:files = [ 'Xfinddir1/foo', \ 'Xfinddir1/bar', \ 'Xfinddir1/Xdir2/foo', @@ -281,4 +283,200 @@ func Test_find_non_existing_path() let &path = save_path endfunc +" Test for 'findexpr' +func Test_findexpr() + CheckUnix + call assert_equal('', &findexpr) + call writefile(['aFile'], 'Xfindexpr1.c', 'D') + call writefile(['bFile'], 'Xfindexpr2.c', 'D') + call writefile(['cFile'], 'Xfindexpr3.c', 'D') + + " basic tests + func FindExpr1() + let fnames = ['Xfindexpr1.c', 'Xfindexpr2.c', 'Xfindexpr3.c'] + return fnames->copy()->filter('v:val =~? v:fname') + endfunc + + set findexpr=FindExpr1() + find Xfindexpr3 + call assert_match('Xfindexpr3.c', @%) + bw! + 2find Xfind + call assert_match('Xfindexpr2.c', @%) + bw! + call assert_fails('4find Xfind', 'E347: No more file "Xfind" found in path') + call assert_fails('find foobar', 'E345: Can''t find file "foobar" in path') + + sfind Xfindexpr2.c + call assert_match('Xfindexpr2.c', @%) + call assert_equal(2, winnr('$')) + %bw! + call assert_fails('sfind foobar', 'E345: Can''t find file "foobar" in path') + + tabfind Xfindexpr3.c + call assert_match('Xfindexpr3.c', @%) + call assert_equal(2, tabpagenr()) + %bw! + call assert_fails('tabfind foobar', 'E345: Can''t find file "foobar" in path') + + " Buffer-local option + set findexpr=['abc'] + new + setlocal findexpr=['def'] + find xxxx + call assert_equal('def', @%) + wincmd w + find xxxx + call assert_equal('abc', @%) + aboveleft new + call assert_equal("['abc']", &findexpr) + wincmd k + aboveleft new + call assert_equal("['abc']", &findexpr) + %bw! + + " Empty list + set findexpr=[] + call assert_fails('find xxxx', 'E345: Can''t find file "xxxx" in path') + + " Error cases + + " Syntax error in the expression + set findexpr=FindExpr1{} + call assert_fails('find Xfindexpr1.c', 'E15: Invalid expression') + + " Find expression throws an error + func FindExpr2() + throw 'find error' + endfunc + set findexpr=FindExpr2() + call assert_fails('find Xfindexpr1.c', 'find error') + + " Try using a null List as the expression + set findexpr=test_null_list() + call assert_fails('find Xfindexpr1.c', 'E345: Can''t find file "Xfindexpr1.c" in path') + + " Try to create a new window from the find expression + func FindExpr3() + new + return ["foo"] + endfunc + set findexpr=FindExpr3() + call assert_fails('find Xfindexpr1.c', 'E565: Not allowed to change text or change window') + + " Try to modify the current buffer from the find expression + func FindExpr4() + call setline(1, ['abc']) + return ["foo"] + endfunc + set findexpr=FindExpr4() + call assert_fails('find Xfindexpr1.c', 'E565: Not allowed to change text or change window') + + " Expression returning a string + set findexpr='abc' + call assert_fails('find Xfindexpr1.c', 'E1514: findexpr did not return a List type') + + set findexpr& + delfunc! FindExpr1 + delfunc! FindExpr2 + delfunc! FindExpr3 + delfunc! FindExpr4 +endfunc + +" Test for using a script-local function for 'findexpr' +func Test_findexpr_scriptlocal_func() + func! s:FindExprScript() + let g:FindExprArg = v:fname + return ['xxx'] + endfunc + + set findexpr=s:FindExprScript() + call assert_equal(expand('') .. 'FindExprScript()', &findexpr) + call assert_equal(expand('') .. 'FindExprScript()', &g:findexpr) + new | only + let g:FindExprArg = '' + find abc + call assert_equal('abc', g:FindExprArg) + bw! + + set findexpr=FindExprScript() + call assert_equal(expand('') .. 'FindExprScript()', &findexpr) + call assert_equal(expand('') .. 'FindExprScript()', &g:findexpr) + new | only + let g:FindExprArg = '' + find abc + call assert_equal('abc', g:FindExprArg) + bw! + + let &findexpr = 's:FindExprScript()' + call assert_equal(expand('') .. 'FindExprScript()', &g:findexpr) + new | only + let g:FindExprArg = '' + find abc + call assert_equal('abc', g:FindExprArg) + bw! + + let &findexpr = 'FindExprScript()' + call assert_equal(expand('') .. 'FindExprScript()', &g:findexpr) + new | only + let g:FindExprArg = '' + find abc + call assert_equal('abc', g:FindExprArg) + bw! + + set findexpr= + setglobal findexpr=s:FindExprScript() + setlocal findexpr= + call assert_equal(expand('') .. 'FindExprScript()', &findexpr) + call assert_equal(expand('') .. 'FindExprScript()', &g:findexpr) + call assert_equal('', &l:findexpr) + new | only + let g:FindExprArg = '' + find abc + call assert_equal('abc', g:FindExprArg) + bw! + + new | only + set findexpr= + setglobal findexpr= + setlocal findexpr=s:FindExprScript() + call assert_equal(expand('') .. 'FindExprScript()', &findexpr) + call assert_equal(expand('') .. 'FindExprScript()', &l:findexpr) + call assert_equal('', &g:findexpr) + let g:FindExprArg = '' + find abc + call assert_equal('abc', g:FindExprArg) + bw! + + set findexpr= + delfunc s:FindExprScript +endfunc + +" Test for expanding the argument to the :find command using 'findexpr' +func Test_findexpr_expand_arg() + func FindExpr1() + let fnames = ['Xfindexpr1.c', 'Xfindexpr2.c', 'Xfindexpr3.c'] + return fnames->copy()->filter('v:val =~? v:fname') + endfunc + set findexpr=FindExpr1() + + call feedkeys(":find \\\"\", "xt") + call assert_equal('"find Xfindexpr1.c', @:) + + call feedkeys(":find Xfind\\\\"\", "xt") + call assert_equal('"find Xfindexpr2.c', @:) + + call feedkeys(":find *3*\\\"\", "xt") + call assert_equal('"find Xfindexpr3.c', @:) + + call feedkeys(":find Xfind\\\"\", "xt") + call assert_equal('"find Xfindexpr1.c Xfindexpr2.c Xfindexpr3.c', @:) + + call feedkeys(":find abc\\\"\", "xt") + call assert_equal('"find abc', @:) + + set findexpr& + delfunc! FindExpr1 +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_functions.vim b/src/testdir/test_functions.vim index 66b8876084..85a34052e4 100644 --- a/src/testdir/test_functions.vim +++ b/src/testdir/test_functions.vim @@ -3416,7 +3416,7 @@ func Test_range() call assert_fails('call term_start(range(3, 4))', 'E474:') let g:terminal_ansi_colors = range(16) if has('win32') - let cmd = "cmd /c dir" + let cmd = "cmd /D /c dir" else let cmd = "ls" endif diff --git a/src/testdir/test_getvar.vim b/src/testdir/test_getvar.vim index 6efb192ebc..2ff13ef6e3 100644 --- a/src/testdir/test_getvar.vim +++ b/src/testdir/test_getvar.vim @@ -22,6 +22,12 @@ func Test_var() call assert_equal('Chance', getwinvar(9, '', def_str)) call assert_equal(0, getwinvar(1, '&nu')) call assert_equal(0, getwinvar(1, '&nu', 1)) + call assert_match(v:t_dict, type(getwinvar(1, '&'))) + call assert_match(v:t_dict, type(getwinvar(1, '&', def_str))) + call assert_equal('', getwinvar(9, '&')) + call assert_equal('Chance', getwinvar(9, '&', def_str)) + call assert_equal('', getwinvar(1, '&nux')) + call assert_equal('Chance', getwinvar(1, '&nux', def_str)) unlet def_str " test for gettabvar() @@ -83,7 +89,12 @@ func Test_var() unlet def_dict + call assert_match(v:t_dict, type(gettabwinvar(2, 3, '&'))) + call assert_match(v:t_dict, type(gettabwinvar(2, 3, '&', 1))) call assert_equal("", gettabwinvar(9, 2020, '')) + call assert_equal(1, gettabwinvar(9, 2020, '', 1)) + call assert_equal('', gettabwinvar(9, 2020, '&')) + call assert_equal(1, gettabwinvar(9, 2020, '&', 1)) call assert_equal('', gettabwinvar(2, 3, '&nux')) call assert_equal(1, gettabwinvar(2, 3, '&nux', 1)) tabonly diff --git a/src/testdir/test_modeline.vim b/src/testdir/test_modeline.vim index 0a7240b896..bb5bc6b515 100644 --- a/src/testdir/test_modeline.vim +++ b/src/testdir/test_modeline.vim @@ -208,6 +208,7 @@ func Test_modeline_fails_always() call s:modeline_fails('equalprg', 'equalprg=Something()', 'E520:') call s:modeline_fails('errorfile', 'errorfile=Something()', 'E520:') call s:modeline_fails('exrc', 'exrc=Something()', 'E520:') + call s:modeline_fails('findexpr', 'findexpr=Something()', 'E520:') call s:modeline_fails('formatprg', 'formatprg=Something()', 'E520:') call s:modeline_fails('fsync', 'fsync=Something()', 'E520:') call s:modeline_fails('grepprg', 'grepprg=Something()', 'E520:') diff --git a/src/testdir/test_options.vim b/src/testdir/test_options.vim index c0e21b70d0..17fb6906fe 100644 --- a/src/testdir/test_options.vim +++ b/src/testdir/test_options.vim @@ -4,6 +4,8 @@ source shared.vim source check.vim source view_util.vim +scriptencoding utf-8 + func Test_whichwrap() set whichwrap=b,s call assert_equal('b,s', &whichwrap) @@ -757,6 +759,9 @@ func Test_set_option_errors() call assert_fails('set tabstop=10000', 'E474:') call assert_fails('let &tabstop = 10000', 'E474:') call assert_fails('set tabstop=5500000000', 'E474:') + if has('terminal') + call assert_fails('set termwinscroll=-1', 'E487:') + endif call assert_fails('set textwidth=-1', 'E487:') call assert_fails('set timeoutlen=-1', 'E487:') call assert_fails('set updatecount=-1', 'E487:') @@ -1044,15 +1049,6 @@ func Test_set_all_one_column() call assert_equal(sort(copy(options)), options) endfunc -func Test_set_values() - " opt_test.vim is generated from ../optiondefs.h using gen_opt_test.vim - if filereadable('opt_test.vim') - source opt_test.vim - else - throw 'Skipped: opt_test.vim does not exist' - endif -endfunc - func Test_renderoptions() " Only do this for Windows Vista and later, fails on Windows XP and earlier. " Doesn't hurt to do this on a non-Windows system. @@ -1586,7 +1582,7 @@ endfunc " Test for changing options in a sandbox func Test_opt_sandbox() - for opt in ['backupdir', 'cdpath', 'exrc'] + for opt in ['backupdir', 'cdpath', 'exrc', 'findexpr'] call assert_fails('sandbox set ' .. opt .. '?', 'E48:') call assert_fails('sandbox let &' .. opt .. ' = 1', 'E48:') endfor diff --git a/src/testdir/test_options_all.vim b/src/testdir/test_options_all.vim new file mode 100644 index 0000000000..a2330ecb90 --- /dev/null +++ b/src/testdir/test_options_all.vim @@ -0,0 +1,13 @@ +" Test for options + +" opt_test.vim is generated from src/optiondefs.h and runtime/doc/options.txt +" using gen_opt_test.vim +if filereadable('opt_test.vim') + source opt_test.vim +else + func Test_set_values() + throw 'Skipped: opt_test.vim does not exist' + endfunc +endif + +" vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_swap.vim b/src/testdir/test_swap.vim index 7532655a36..4ba7bb6c16 100644 --- a/src/testdir/test_swap.vim +++ b/src/testdir/test_swap.vim @@ -420,7 +420,7 @@ func s:get_unused_pid(base) if has('job') " Execute 'echo' as a temporary job, and return its pid as an unused pid. if has('win32') - let cmd = 'cmd /c echo' + let cmd = 'cmd /D /c echo' else let cmd = 'echo' endif diff --git a/src/testdir/test_termcodes.vim b/src/testdir/test_termcodes.vim index 507753c21a..2b44b15535 100644 --- a/src/testdir/test_termcodes.vim +++ b/src/testdir/test_termcodes.vim @@ -2001,6 +2001,12 @@ func Test_xx08_kitty_response() \ kitty: 'y', \ }, terminalprops()) + call feedkeys("\[?1u") " simulate the kitty keyboard protocol is enabled + call feedkeys(':' .. GetEscCodeCSIu('V', '5') .. GetEscCodeCSIuWithoutModifier("\") .. "\\"\", 'Lx!') + call assert_equal("\"\", @:) + call feedkeys(':' .. GetEscCodeCSIu('V', '5') .. GetEscCodeCSIu("\", '129') .. "\\"\", 'Lx!') + call assert_equal("\"\", @:) + set t_RV= call test_override('term_props', 0) endfunc diff --git a/src/testdir/test_terminal.vim b/src/testdir/test_terminal.vim index 87c58aee73..d8c9f8e255 100644 --- a/src/testdir/test_terminal.vim +++ b/src/testdir/test_terminal.vim @@ -320,10 +320,10 @@ endfunc func Get_cat_123_cmd() if has('win32') if !has('conpty') - return 'cmd /c "cls && color 2 && echo 123"' + return 'cmd /D /c "cls && color 2 && echo 123"' else " When clearing twice, extra sequence is not output. - return 'cmd /c "cls && cls && color 2 && echo 123"' + return 'cmd /D /c "cls && cls && color 2 && echo 123"' endif else call writefile(["\[32m123"], 'Xtext') @@ -410,7 +410,7 @@ func Test_terminal_scrape_multibyte() if has('win32') " Run cmd with UTF-8 codepage to make the type command print the expected " multibyte characters. - let buf = term_start("cmd /K chcp 65001") + let buf = term_start("cmd /D /K chcp 65001") call term_sendkeys(buf, "type Xtext\") eval buf->term_sendkeys("exit\") let line = 4 @@ -457,7 +457,7 @@ endfunc func Test_terminal_scroll() call writefile(range(1, 200), 'Xtext', 'D') if has('win32') - let cmd = 'cmd /c "type Xtext"' + let cmd = 'cmd /D /c "type Xtext"' else let cmd = "cat Xtext" endif @@ -501,6 +501,21 @@ func Test_terminal_scrollback() let lines = line('$') call assert_inrange(91, 100, lines) + " When 'termwinscroll' becomes small, the scrollback should become small. + set termwinscroll=20 + call term_sendkeys(buf, "echo set20\") + call WaitForAssert({-> assert_true([term_getline(buf, rows - 1), term_getline(buf, rows - 2)]->index('set20') >= 0)}) + let lines = line('$') + call assert_inrange(19, 20, lines) + + " When 'termwinscroll' under 10 which means 10% of it will be 0, + " the scrollback should become small. + set termwinscroll=1 + call term_sendkeys(buf, "echo set1\") + call WaitForAssert({-> assert_true([term_getline(buf, rows - 1), term_getline(buf, rows - 2)]->index('set1') >= 0)}) + let lines = line('$') + call assert_inrange(1, 2, lines) + call StopShellInTerminal(buf) exe buf . 'bwipe' set termwinscroll& @@ -765,7 +780,7 @@ endfunc func Test_terminal_cwd() if has('win32') - let cmd = 'cmd /c cd' + let cmd = 'cmd /D /c cd' else CheckExecutable pwd let cmd = 'pwd' @@ -1111,7 +1126,7 @@ func Test_terminal_composing_unicode() set encoding=utf-8 if has('win32') - let cmd = "cmd /K chcp 65001" + let cmd = "cmd /D /K chcp 65001" let lnum = [3, 6, 9] else let cmd = &shell diff --git a/src/testdir/test_terminal2.vim b/src/testdir/test_terminal2.vim index 05b228ed7d..166b1792d3 100644 --- a/src/testdir/test_terminal2.vim +++ b/src/testdir/test_terminal2.vim @@ -450,7 +450,7 @@ func Test_terminal_does_not_truncate_last_newlines() for c in contents call writefile(c, 'Xdntfile', 'D') if has('win32') - term cmd /c type Xdntfile + term cmd /D /c type Xdntfile else term cat Xdntfile endif @@ -465,7 +465,7 @@ endfunc func GetDummyCmd() if has('win32') - return 'cmd /c ""' + return 'cmd /D /c ""' else CheckExecutable false return 'false' diff --git a/src/testdir/test_window_cmd.vim b/src/testdir/test_window_cmd.vim index 91adb9b1d0..c8afab325f 100644 --- a/src/testdir/test_window_cmd.vim +++ b/src/testdir/test_window_cmd.vim @@ -557,7 +557,7 @@ func Test_equalalways_on_close() 1wincmd w split 4wincmd w - resize + 5 + resize +5 " left column has three windows, equalized heights. " right column has two windows, top one a bit higher let height_1 = winheight(1) diff --git a/src/testdir/test_windows_home.vim b/src/testdir/test_windows_home.vim index 7db5395f3d..ceed25a4d4 100644 --- a/src/testdir/test_windows_home.vim +++ b/src/testdir/test_windows_home.vim @@ -105,7 +105,7 @@ func Test_WindowsHome() RestoreEnv let $HOME = save_home let env = '' - let job = job_start('cmd /c set', {'out_cb': {ch,x->[env,execute('let env=x')]}}) + let job = job_start('cmd /D /c set', {'out_cb': {ch,x->[env,execute('let env=x')]}}) sleep 1 let env = filter(split(env, "\n"), 'v:val=="HOME"') let home = len(env) == 0 ? "" : env[0] diff --git a/src/testdir/test_xxd.vim b/src/testdir/test_xxd.vim index 5706871519..f10c2447db 100644 --- a/src/testdir/test_xxd.vim +++ b/src/testdir/test_xxd.vim @@ -485,12 +485,12 @@ func Test_xxd_little_endian_with_cols() enew! call writefile(["ABCDEF"], 'Xxdin', 'D') exe 'r! ' .. s:xxd_cmd .. ' -e -c6 ' .. ' Xxdin' - call assert_equal('00000000: 44434241 4645 ABCDEF', getline(2)) + call assert_equal('00000000: 44434241 4645 ABCDEF', getline(2)) enew! call writefile(["ABCDEFGHI"], 'Xxdin', 'D') exe 'r! ' .. s:xxd_cmd .. ' -e -c9 ' .. ' Xxdin' - call assert_equal('00000000: 44434241 48474645 49 ABCDEFGHI', getline(2)) + call assert_equal('00000000: 44434241 48474645 49 ABCDEFGHI', getline(2)) bwipe! endfunc diff --git a/src/testdir/viewdumps.vim b/src/testdir/viewdumps.vim index 62f7bbe71b..ffb7314e14 100644 --- a/src/testdir/viewdumps.vim +++ b/src/testdir/viewdumps.vim @@ -8,4 +8,4 @@ g:Init('\', 0) # Match ":language" of runtest.vim. language messages C -# vim:fdm=syntax:sw=2:ts=8:noet:nolist:nosta: +# vim:fdm=syntax:sw=2:ts=8:noet:nosta: diff --git a/src/version.c b/src/version.c index 7aeeb8efb4..1c00d91522 100644 --- a/src/version.c +++ b/src/version.c @@ -719,6 +719,58 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 813, +/**/ + 812, +/**/ + 811, +/**/ + 810, +/**/ + 809, +/**/ + 808, +/**/ + 807, +/**/ + 806, +/**/ + 805, +/**/ + 804, +/**/ + 803, +/**/ + 802, +/**/ + 801, +/**/ + 800, +/**/ + 799, +/**/ + 798, +/**/ + 797, +/**/ + 796, +/**/ + 795, +/**/ + 794, +/**/ + 793, +/**/ + 792, +/**/ + 791, +/**/ + 790, +/**/ + 789, +/**/ + 788, /**/ 787, /**/ diff --git a/src/viminfo.c b/src/viminfo.c index 11a2946816..2196d3c426 100644 --- a/src/viminfo.c +++ b/src/viminfo.c @@ -552,25 +552,32 @@ read_viminfo_history(vir_T *virp, int writing) // Need to re-allocate to append the separator byte. len = STRLEN(val); - p = alloc(len + 2); - if (p == NULL) - goto done; - if (type == HIST_SEARCH) { + p = alloc((size_t)len + 1); // +1 for the NUL. val already + // includes the separator. + if (p == NULL) + goto done; + // Search entry: Move the separator from the first // column to after the NUL. mch_memmove(p, val + 1, (size_t)len); p[len] = sep; + --len; // take into account the shortened string } else { + p = alloc((size_t)len + 2); // +1 for NUL and +1 for separator + if (p == NULL) + goto done; + // Not a search entry: No separator in the viminfo // file, add a NUL separator. - mch_memmove(p, val, (size_t)len + 1); - p[len + 1] = NUL; + mch_memmove(p, val, (size_t)len + 1); // +1 to include the NUL + p[len + 1] = NUL; // put the separator *after* the string's NUL } viminfo_history[type][viminfo_hisidx[type]].hisstr = p; + viminfo_history[type][viminfo_hisidx[type]].hisstrlen = (size_t)len; viminfo_history[type][viminfo_hisidx[type]].time_set = 0; viminfo_history[type][viminfo_hisidx[type]].viminfo = TRUE; viminfo_history[type][viminfo_hisidx[type]].hisnum = 0; @@ -629,8 +636,9 @@ handle_viminfo_history( for (idx = 0; idx < viminfo_hisidx[type]; ++idx) { p = viminfo_history[type][idx].hisstr; + len = viminfo_history[type][idx].hisstrlen; if (STRCMP(val, p) == 0 - && (type != HIST_SEARCH || sep == p[STRLEN(p) + 1])) + && (type != HIST_SEARCH || sep == p[len + 1])) { overwrite = TRUE; break; @@ -654,6 +662,7 @@ handle_viminfo_history( // Put the separator after the NUL. p[len + 1] = sep; viminfo_history[type][idx].hisstr = p; + viminfo_history[type][idx].hisstrlen = (size_t)len; viminfo_history[type][idx].hisnum = 0; viminfo_history[type][idx].viminfo = TRUE; viminfo_hisidx[type]++; @@ -699,6 +708,7 @@ concat_history(int type) { vim_free(histentry[idx].hisstr); histentry[idx].hisstr = viminfo_history[type][i].hisstr; + histentry[idx].hisstrlen = viminfo_history[type][i].hisstrlen; histentry[idx].viminfo = TRUE; histentry[idx].time_set = viminfo_history[type][i].time_set; if (--idx < 0) @@ -768,6 +778,7 @@ merge_history(int type) { new_hist[i] = *tot_hist[i]; tot_hist[i]->hisstr = NULL; + tot_hist[i]->hisstrlen = 0; if (new_hist[i].hisnum == 0) new_hist[i].hisnum = ++*hisnum; } @@ -778,9 +789,15 @@ merge_history(int type) // Free what is not kept. for (i = 0; i < viminfo_hisidx[type]; i++) + { vim_free(viminfo_history[type][i].hisstr); + viminfo_history[type][i].hisstrlen = 0; + } for (i = 0; i < hislen; i++) + { vim_free(histentry[i].hisstr); + histentry[i].hisstrlen = 0; + } vim_free(histentry); set_histentry(type, new_hist); vim_free(tot_hist); @@ -867,20 +884,30 @@ write_viminfo_history(FILE *fp, int merge) && !(round == 2 && i >= viminfo_hisidx[type])) { char_u *p; + size_t plen; time_t timestamp; int c = NUL; if (round == 1) { p = histentry[i].hisstr; + plen = histentry[i].hisstrlen; timestamp = histentry[i].time_set; } else { - p = viminfo_history[type] == NULL ? NULL - : viminfo_history[type][i].hisstr; - timestamp = viminfo_history[type] == NULL ? 0 - : viminfo_history[type][i].time_set; + if (viminfo_history[type] == NULL) + { + p = NULL; + plen = 0; + timestamp = 0; + } + else + { + p = viminfo_history[type][i].hisstr; + plen = viminfo_history[type][i].hisstrlen; + timestamp = viminfo_history[type][i].time_set; + } } if (p != NULL && (round == 2 @@ -893,7 +920,7 @@ write_viminfo_history(FILE *fp, int merge) // second column; use a space if there isn't one. if (type == HIST_SEARCH) { - c = p[STRLEN(p) + 1]; + c = p[plen + 1]; putc(c == NUL ? ' ' : c, fp); } viminfo_writestring(fp, p); @@ -931,7 +958,10 @@ write_viminfo_history(FILE *fp, int merge) } for (i = 0; i < viminfo_hisidx[type]; ++i) if (viminfo_history[type] != NULL) + { vim_free(viminfo_history[type][i].hisstr); + viminfo_history[type][i].hisstrlen = 0; + } VIM_CLEAR(viminfo_history[type]); viminfo_hisidx[type] = 0; } @@ -1112,6 +1142,7 @@ barline_parse(vir_T *virp, char_u *text, garray_T *values) // freed later, also need to free "buf" later value->bv_tofree = buf; s = sconv; + len = STRLEN(s); converted = TRUE; } } @@ -1119,7 +1150,7 @@ barline_parse(vir_T *virp, char_u *text, garray_T *values) // Need to copy in allocated memory if the string wasn't allocated // above and we did allocate before, thus vir_line may change. if (s != buf && allocated && !converted) - s = vim_strsave(s); + s = vim_strnsave(s, len); value->bv_string = s; value->bv_type = BVAL_STRING; value->bv_len = len; diff --git a/src/window.c b/src/window.c index db907f8a48..7c8f4fb366 100644 --- a/src/window.c +++ b/src/window.c @@ -7925,23 +7925,38 @@ int_cmp(const void *pa, const void *pb) } /* - * Handle setting 'colorcolumn' or 'textwidth' in window "wp". + * Check "cc" as 'colorcolumn' and update the members of "wp". + * This is called when 'colorcolumn' or 'textwidth' is changed. * Returns error message, NULL if it's OK. */ char * -check_colorcolumn(win_T *wp) +check_colorcolumn( + char_u *cc, // when NULL: use "wp->w_p_cc" + win_T *wp) // when NULL: only parse "cc" { - char_u *s; + char_u *s = empty_option; + int tw; int col; int count = 0; int color_cols[256]; int i; int j = 0; - if (wp->w_buffer == NULL) + if (wp != NULL && wp->w_buffer == NULL) return NULL; // buffer was closed - for (s = wp->w_p_cc; *s != NUL && count < 255;) + if (cc != NULL) + s = cc; + else if (wp != NULL) + s = wp->w_p_cc; + + if (wp != NULL) + tw = wp->w_buffer->b_p_tw; + else + // buffer-local value not set, assume zero + tw = 0; + + while (*s != NUL && count < 255) { if (*s == '-' || *s == '+') { @@ -7951,9 +7966,9 @@ check_colorcolumn(win_T *wp) if (!VIM_ISDIGIT(*s)) return e_invalid_argument; col = col * getdigits(&s); - if (wp->w_buffer->b_p_tw == 0) + if (tw == 0) goto skip; // 'textwidth' not set, skip this item - col += wp->w_buffer->b_p_tw; + col += tw; if (col < 0) goto skip; } @@ -7971,6 +7986,9 @@ check_colorcolumn(win_T *wp) return e_invalid_argument; // illegal trailing comma as in "set cc=80," } + if (wp == NULL) + return NULL; // only parse "cc" + vim_free(wp->w_p_cc_cols); if (count == 0) wp->w_p_cc_cols = NULL; diff --git a/src/xxd/xxd.c b/src/xxd/xxd.c index 63f516c12b..b1050e9da4 100644 --- a/src/xxd/xxd.c +++ b/src/xxd/xxd.c @@ -64,6 +64,7 @@ * 10.02.2024 fix buffer-overflow when writing color output to buffer, #14003 * 10.05.2024 fix another buffer-overflow when writing colored output to buffer, #14738 * 10.09.2024 Support -b and -i together, #15661 + * 19.10.2024 -e did add an extra space #15899 * * (c) 1990-1998 by Juergen Weigert (jnweiger@gmail.com) * @@ -144,7 +145,7 @@ extern void perror __P((char *)); # endif #endif -char version[] = "xxd 2024-09-15 by Juergen Weigert et al."; +char version[] = "xxd 2024-10-19 by Juergen Weigert et al."; #ifdef WIN32 char osver[] = " (Win32)"; #else @@ -1110,9 +1111,6 @@ main(int argc, char *argv[]) else c = addrlen + 3 + (grplen * cols - 1)/octspergrp + p*12; - if (hextype == HEX_LITTLEENDIAN) - c += 1; - COLOR_PROLOGUE begin_coloring_char(l,&c,e,ebcdic); #if defined(__MVS__) && __CHARSET_LIB == 0 @@ -1126,21 +1124,15 @@ main(int argc, char *argv[]) l[c++] = (e > 31 && e < 127) ? e : '.'; #endif COLOR_EPILOGUE - n++; - if (++p == cols) - { - l[c++] = '\n'; - l[c++] = '\0'; - xxdline(fpo, l, autoskip ? nonzero : 1); - nonzero = 0; - p = 0; - } } else /*no colors*/ { if (ebcdic) e = (e < 64) ? '.' : etoa64[e-64]; + if (hextype == HEX_LITTLEENDIAN) + c -= 1; + c += addrlen + 3 + p; l[c++] = #if defined(__MVS__) && __CHARSET_LIB == 0 @@ -1149,16 +1141,16 @@ main(int argc, char *argv[]) (e > 31 && e < 127) #endif ? e : '.'; - n++; - if (++p == cols) - { - l[c++] = '\n'; - l[c] = '\0'; - xxdline(fpo, l, autoskip ? nonzero : 1); - nonzero = 0; - p = 0; - } } + n++; + if (++p == cols) + { + l[c++] = '\n'; + l[c] = '\0'; + xxdline(fpo, l, autoskip ? nonzero : 1); + nonzero = 0; + p = 0; + } } if (p) { @@ -1166,8 +1158,6 @@ main(int argc, char *argv[]) l[c] = '\0'; if (color) { - c++; - x = p; if (hextype == HEX_LITTLEENDIAN) {