diff options
66 files changed, 940 insertions, 338 deletions
diff --git a/ci/build.ps1 b/ci/build.ps1 index a81d351bc6..ef5ba3bf2d 100644 --- a/ci/build.ps1 +++ b/ci/build.ps1 @@ -86,19 +86,10 @@ elseif ($compiler -eq 'MSVC') { } if (-not $NoTests) { - # Setup python (use AppVeyor system python) - - # Disambiguate python3, if needed - if (-not (Test-Path -Path C:\hostedtoolcache\windows\Python\3.5.4\x64\python3.exe) ) { - move C:\hostedtoolcache\windows\Python\3.5.4\x64\python.exe C:\hostedtoolcache\windows\Python\3.5.4\x64\python3.exe - } - $env:PATH = "C:\hostedtoolcache\windows\Python\2.7.18\x64;C:\hostedtoolcache\windows\Python\3.5.4\x64;$env:PATH" - + python -m ensurepip python -m pip install pynvim ; exitIfFailed - python3 -m pip install pynvim ; exitIfFailed # Sanity check python -c "import pynvim; print(str(pynvim))" ; exitIfFailed - python3 -c "import pynvim; print(str(pynvim))" ; exitIfFailed gem.cmd install --pre neovim Get-Command -CommandType Application neovim-ruby-host.bat diff --git a/runtime/autoload/dist/ft.vim b/runtime/autoload/dist/ft.vim index 0d6841a35b..69712046a5 100644 --- a/runtime/autoload/dist/ft.vim +++ b/runtime/autoload/dist/ft.vim @@ -67,13 +67,29 @@ func dist#ft#FTasmsyntax() endif endfunc -" Check if one of the first five lines contains "VB_Name". In that case it is -" probably a Visual Basic file. Otherwise it's assumed to be "alt" filetype. -func dist#ft#FTVB(alt) - if getline(1).getline(2).getline(3).getline(4).getline(5) =~? 'VB_Name\|Begin VB\.\(Form\|MDIForm\|UserControl\)' +func dist#ft#FTbas() + if exists("g:filetype_bas") + exe "setf " . g:filetype_bas + return + endif + + " most frequent FreeBASIC-specific keywords in distro files + let fb_keywords = '\c^\s*\%(extern\|var\|enum\|private\|scope\|union\|byref\|operator\|constructor\|delete\|namespace\|public\|property\|with\|destructor\|using\)\>\%(\s*[:=(]\)\@!' + let fb_preproc = '\c^\s*\%(#\a\+\|option\s\+\%(byval\|dynamic\|escape\|\%(no\)\=gosub\|nokeyword\|private\|static\)\>\)' + let fb_comment = "^\\s*/'" + " OPTION EXPLICIT, without the leading underscore, is common to many dialects + let qb64_preproc = '\c^\s*\%($\a\+\|option\s\+\%(_explicit\|_\=explicitarray\)\>\)' + + let lines = getline(1, min([line("$"), 100])) + + if match(lines, fb_preproc) > -1 || match(lines, fb_comment) > -1 || match(lines, fb_keywords) > -1 + setf freebasic + elseif match(lines, qb64_preproc) > -1 + setf qb64 + elseif match(lines, '\cVB_Name\|Begin VB\.\(Form\|MDIForm\|UserControl\)') > -1 setf vb else - exe "setf " . a:alt + setf basic endif endfunc diff --git a/runtime/doc/diff.txt b/runtime/doc/diff.txt index 6115a5d235..abe99102ee 100644 --- a/runtime/doc/diff.txt +++ b/runtime/doc/diff.txt @@ -324,8 +324,9 @@ After setting this variable, reload the syntax script: > FINDING THE DIFFERENCES *diff-diffexpr* -The 'diffexpr' option can be set to use something else than the standard -"diff" program to compare two files and find the differences. *E959* +The 'diffexpr' option can be set to use something else than the internal diff +support or the standard "diff" program to compare two files and find the +differences. When 'diffexpr' is empty, Vim uses this command to find the differences between file1 and file2: > @@ -358,7 +359,7 @@ format mentioned. These variables are set to the file names used: v:fname_in original file v:fname_new new version of the same file - v:fname_out resulting diff file + v:fname_out where to write the resulting diff file Additionally, 'diffexpr' should take care of "icase" and "iwhite" in the 'diffopt' option. 'diffexpr' cannot change the value of 'lines' and diff --git a/runtime/doc/editing.txt b/runtime/doc/editing.txt index b5a7a193a5..44987f3b7b 100644 --- a/runtime/doc/editing.txt +++ b/runtime/doc/editing.txt @@ -845,7 +845,7 @@ Note: When the 'write' option is off, you are not able to write any file. *:w* *:write* *E502* *E503* *E504* *E505* - *E512* *E514* *E667* *E796* *E949* + *E512* *E514* *E667* *E949* :w[rite] [++opt] Write the whole buffer to the current file. This is the normal way to save changes to a file. It fails when the 'readonly' option is set or when there is diff --git a/runtime/doc/filetype.txt b/runtime/doc/filetype.txt index fdd9c8c12e..5486c87af9 100644 --- a/runtime/doc/filetype.txt +++ b/runtime/doc/filetype.txt @@ -131,14 +131,15 @@ shell script: "#!/bin/csh". argument was used. *filetype-overrule* -When the same extension is used for two filetypes, Vim tries to guess what -kind of file it is. This doesn't always work. A number of global variables -can be used to overrule the filetype used for certain extensions: +When the same extension is used for multiple filetypes, Vim tries to guess +what kind of file it is. This doesn't always work. A number of global +variables can be used to overrule the filetype used for certain extensions: file name variable ~ *.asa g:filetype_asa |ft-aspvbs-syntax| |ft-aspperl-syntax| *.asm g:asmsyntax |ft-asm-syntax| *.asp g:filetype_asp |ft-aspvbs-syntax| |ft-aspperl-syntax| + *.bas g:filetype_bas |ft-basic-syntax| *.fs g:filetype_fs |ft-forth-syntax| *.i g:filetype_i |ft-progress-syntax| *.inc g:filetype_inc diff --git a/runtime/doc/fold.txt b/runtime/doc/fold.txt index 80c934d13b..8bc47a3b10 100644 --- a/runtime/doc/fold.txt +++ b/runtime/doc/fold.txt @@ -501,7 +501,9 @@ Note the use of backslashes to avoid some characters to be interpreted by the :endfunction Evaluating 'foldtext' is done in the |sandbox|. The current window is set to -the window that displays the line. Errors are ignored. +the window that displays the line. + +Errors are ignored. For debugging set the 'debug' option to "throw". The default value is |foldtext()|. This returns a reasonable text for most types of folding. If you don't like it, you can specify your own 'foldtext' diff --git a/runtime/doc/intro.txt b/runtime/doc/intro.txt index 0e0156ac6b..54999fa163 100644 --- a/runtime/doc/intro.txt +++ b/runtime/doc/intro.txt @@ -322,7 +322,6 @@ notation meaning equivalent decimal value(s) ~ <Bar> vertical bar | 124 *<Bar>* <Del> delete 127 <CSI> command sequence intro ALT-Esc 155 *<CSI>* -<xCSI> CSI when typed in the GUI *<xCSI>* <EOL> end-of-line (can be <CR>, <NL> or <CR><NL>, depends on system and 'fileformat') *<EOL>* diff --git a/runtime/doc/map.txt b/runtime/doc/map.txt index d83682b02b..9244638788 100644 --- a/runtime/doc/map.txt +++ b/runtime/doc/map.txt @@ -1217,7 +1217,7 @@ scripts. *:command-verbose* When 'verbose' is non-zero, listing a command will also display where it was -last defined. Example: > +last defined and any completion argument. Example: > :verbose command TOhtml < Name Args Range Complete Definition ~ @@ -1332,6 +1332,8 @@ completion can be enabled: -complete=custom,{func} custom completion, defined via {func} -complete=customlist,{func} custom completion, defined via {func} +If you specify completion while there is nothing to complete (-nargs=0, the +default) then you get error *E1208* . Note: That some completion methods might expand environment variables. @@ -1434,6 +1436,9 @@ There are some special cases as well: -register The first argument to the command can be an optional register name (like :del, :put, :yank). -buffer The command will only be available in the current buffer. + -keepscript Do not use the location of where the user command was + defined for verbose messages, use the location of where + the user command was invoked. In the cases of the -count and -register attributes, if the optional argument is supplied, it is removed from the argument list and is available to the diff --git a/runtime/doc/nvim_terminal_emulator.txt b/runtime/doc/nvim_terminal_emulator.txt index bfacbe19f5..f322764ecf 100644 --- a/runtime/doc/nvim_terminal_emulator.txt +++ b/runtime/doc/nvim_terminal_emulator.txt @@ -162,12 +162,11 @@ command name, for example: > This opens two windows: gdb window A terminal window in which "gdb vim" is executed. Here you - can directly interact with gdb. The buffer name is "!gdb". + can directly interact with gdb. program window A terminal window for the executed program. When "run" is used in gdb the program I/O will happen in this window, so - that it does not interfere with controlling gdb. The buffer - name is "gdb program". + that it does not interfere with controlling gdb. The current window is used to show the source code. When gdb pauses the source file location will be displayed, if possible. A sign is used to diff --git a/runtime/doc/starting.txt b/runtime/doc/starting.txt index 8e5b834088..978142a1e0 100644 --- a/runtime/doc/starting.txt +++ b/runtime/doc/starting.txt @@ -188,7 +188,7 @@ argument. changes and writing. -e *-e* *-E* --E Start Nvim in Ex mode |gQ|. +-E Start Nvim in Ex mode |gQ|, see |Ex-mode|. If stdin is not a TTY: -e reads/executes stdin as Ex commands. diff --git a/runtime/doc/syntax.txt b/runtime/doc/syntax.txt index 2c5531411d..be1586ab41 100644 --- a/runtime/doc/syntax.txt +++ b/runtime/doc/syntax.txt @@ -920,12 +920,16 @@ in .../after/syntax/baan.vim (see |after-directory|). Eg: > BASIC *basic.vim* *vb.vim* *ft-basic-syntax* *ft-vb-syntax* -Both Visual Basic and "normal" basic use the extension ".bas". To detect +Both Visual Basic and "normal" BASIC use the extension ".bas". To detect which one should be used, Vim checks for the string "VB_Name" in the first five lines of the file. If it is not found, filetype will be "basic", otherwise "vb". Files with the ".frm" extension will always be seen as Visual Basic. +If the automatic detection doesn't work for you or you only edit, for +example, FreeBASIC files, use this in your startup vimrc: > + :let filetype_bas = "freebasic" + C *c.vim* *ft-c-syntax* diff --git a/runtime/filetype.vim b/runtime/filetype.vim index 73237437dc..2a0a5110f2 100644 --- a/runtime/filetype.vim +++ b/runtime/filetype.vim @@ -1,7 +1,7 @@ " Vim support file to detect file types " " Maintainer: Bram Moolenaar <Bram@vim.org> -" Last Change: 2022 Jan 13 +" Last Change: 2022 Jan 23 " Listen very carefully, I will say this only once if exists("did_load_filetypes") @@ -189,7 +189,8 @@ au BufNewFile,BufRead *.awk,*.gawk setf awk au BufNewFile,BufRead *.mch,*.ref,*.imp setf b " BASIC or Visual Basic -au BufNewFile,BufRead *.bas call dist#ft#FTVB("basic") +au BufNewFile,BufRead *.bas call dist#ft#FTbas() +au BufNewFile,BufRead *.bi,*.bm call dist#ft#FTbas() " Visual Basic Script (close to Visual Basic) or Visual Basic .NET au BufNewFile,BufRead *.vb,*.vbs,*.dsm,*.ctl setf vb @@ -198,7 +199,7 @@ au BufNewFile,BufRead *.vb,*.vbs,*.dsm,*.ctl setf vb au BufNewFile,BufRead *.iba,*.ibi setf ibasic " FreeBasic file (similar to QBasic) -au BufNewFile,BufRead *.fb,*.bi setf freebasic +au BufNewFile,BufRead *.fb setf freebasic " Batch file for MSDOS. au BufNewFile,BufRead *.bat,*.sys setf dosbatch @@ -649,6 +650,9 @@ au BufNewFile,BufRead *.fsl setf framescript " FStab au BufNewFile,BufRead fstab,mtab setf fstab +" Fusion +au BufRead,BufNewFile *.fusion setf fusion + " F# or Forth au BufNewFile,BufRead *.fs call dist#ft#FTfs() @@ -661,6 +665,12 @@ au BufNewFile,BufRead .gdbinit,gdbinit setf gdb " GDMO au BufNewFile,BufRead *.mo,*.gdmo setf gdmo +" GDscript +au BufNewFile,BufRead *.gd setf gdscript + +" Godot resource +au BufRead,BufNewFile *.tscn,*.tres setf gdresource + " Gedcom au BufNewFile,BufRead *.ged,lltxxxxx.txt setf gedcom @@ -673,8 +683,10 @@ autocmd BufRead,BufNewFile *.gift setf gift " Git au BufNewFile,BufRead COMMIT_EDITMSG,MERGE_MSG,TAG_EDITMSG setf gitcommit au BufNewFile,BufRead NOTES_EDITMSG,EDIT_DESCRIPTION setf gitcommit -au BufNewFile,BufRead *.git/config,.gitconfig,/etc/gitconfig setf gitconfig +au BufNewFile,BufRead *.git/config,.gitconfig,*/etc/gitconfig setf gitconfig au BufNewFile,BufRead */.config/git/config setf gitconfig +au BufNewFile,BufRead *.git/config.worktree setf gitconfig +au BufNewFile,BufRead *.git/worktrees/*/config.worktree setf gitconfig au BufNewFile,BufRead .gitmodules,*.git/modules/*/config setf gitconfig if !empty($XDG_CONFIG_HOME) au BufNewFile,BufRead $XDG_CONFIG_HOME/git/config setf gitconfig @@ -689,6 +701,9 @@ au BufNewFile,BufRead *.git/* " Gkrellmrc au BufNewFile,BufRead gkrellmrc,gkrellmrc_? setf gkrellmrc +" GLSL +au BufNewFile,BufRead *.glsl setf glsl + " GP scripts (2.0 and onward) au BufNewFile,BufRead *.gp,.gprc setf gp @@ -709,15 +724,19 @@ au BufNewFile,BufRead gitolite.conf setf gitolite au BufNewFile,BufRead {,.}gitolite.rc,example.gitolite.rc setf perl " Gnuplot scripts -au BufNewFile,BufRead *.gpi setf gnuplot +au BufNewFile,BufRead *.gpi,.gnuplot setf gnuplot " Go (Google) au BufNewFile,BufRead *.go setf go au BufNewFile,BufRead Gopkg.lock setf toml +au BufRead,BufNewFile go.work setf gowork " GrADS scripts au BufNewFile,BufRead *.gs setf grads +" GraphQL +au BufNewFile,BufRead *.graphql,*.graphqls,*.gql setf graphql + " Gretl au BufNewFile,BufRead *.gretl setf gretl @@ -733,12 +752,18 @@ au BufNewFile,BufRead */etc/group,*/etc/group-,*/etc/group.edit,*/etc/gshadow,*/ " GTK RC au BufNewFile,BufRead .gtkrc,gtkrc setf gtkrc +" Hack +au BufRead,BufNewFile *.hack,*.hackpartial setf hack + " Haml au BufNewFile,BufRead *.haml setf haml " Hamster Classic | Playground files au BufNewFile,BufRead *.hsm setf hamster +" Handlebars +au BufNewFile,BufRead *.hbs setf handlebars + " Haskell au BufNewFile,BufRead *.hs,*.hsc,*.hs-boot,*.hsig setf haskell au BufNewFile,BufRead *.lhs setf lhaskell @@ -751,12 +776,21 @@ au BufNewFile,BufRead cabal.config setf cabalconfig au BufNewFile,BufRead *.ht setf haste au BufNewFile,BufRead *.htpp setf hastepreproc +" HCL +au BufRead,BufNewFile *.hcl setf hcl + " Hercules au BufNewFile,BufRead *.vc,*.ev,*.sum,*.errsum setf hercules +" HEEx +au BufRead,BufNewFile *.heex setf heex + " HEX (Intel) au BufNewFile,BufRead *.hex,*.h32 setf hex +" Hjson +au BufNewFile,BufRead *.hjson setf hjson + " Hollywood au BufRead,BufNewFile *.hws setf hollywood @@ -881,6 +915,9 @@ au BufNewFile,BufRead *.jov,*.j73,*.jovial setf jovial " JSON au BufNewFile,BufRead *.json,*.jsonp,*.webmanifest setf json +" JSON5 +au BufNewFile,BufRead *.json5 setf json5 + " JSON Patch (RFC 6902) au BufNewFile,BufRead *.json-patch setf json @@ -932,6 +969,9 @@ au BufNewFile,BufRead *.ldif setf ldif " Ld loader au BufNewFile,BufRead *.ld setf ld +" Ledger +au BufRead,BufNewFile *.ldg,*.ledger,*.journal setf ledger + " Less au BufNewFile,BufRead *.less setf less @@ -1169,6 +1209,9 @@ au BufNewFile,BufRead *.nginx,nginx*.conf,*nginx.conf,*/etc/nginx/*,*/usr/local/ " Ninja file au BufNewFile,BufRead *.ninja setf ninja +" Nix +au BufRead,BufNewFile *.nix setf nix + " NPM RC file au BufNewFile,BufRead npmrc,.npmrc setf dosini @@ -1354,6 +1397,9 @@ au BufNewFile,BufRead *printcap au BufNewFile,BufRead *termcap \ let b:ptcap_type = "term" | setf ptcap +" Prisma +au BufRead,BufNewFile *.prisma setf prisma + " PCCTS / ANTLR "au BufNewFile,BufRead *.g setf antlr au BufNewFile,BufRead *.g setf pccts @@ -1361,6 +1407,9 @@ au BufNewFile,BufRead *.g setf pccts " PPWizard au BufNewFile,BufRead *.it,*.ih setf ppwiz +" Pug +au BufRead,BufNewFile *.pug setf pug + " Puppet au BufNewFile,BufRead Puppetfile setf ruby @@ -1426,6 +1475,9 @@ au BufNewFile,BufRead *.pyx,*.pxd setf pyrex au BufNewFile,BufRead *.py,*.pyw,.pythonstartup,.pythonrc setf python au BufNewFile,BufRead *.ptl,*.pyi,SConstruct setf python +" QL +au BufRead,BufNewFile *.ql,*.qll setf ql + " Radiance au BufNewFile,BufRead *.rad,*.mat setf radiance @@ -1830,6 +1882,9 @@ au BufNewFile,BufRead */etc/sudoers,sudoers.tmp setf sudoers " SVG (Scalable Vector Graphics) au BufNewFile,BufRead *.svg setf svg +" Surface +au BufRead,BufNewFile *.sface setf surface + " Tads (or Nroff or Perl test file) au BufNewFile,BufRead *.t \ if !dist#ft#FTnroff() && !dist#ft#FTperl() | setf tads | endif @@ -1847,6 +1902,9 @@ au BufRead,BufNewFile *.task setf taskedit " Tcl (JACL too) au BufNewFile,BufRead *.tcl,*.tm,*.tk,*.itcl,*.itk,*.jacl,.tclshrc,.wishrc setf tcl +" Teal +au BufRead,BufNewFile *.tl setf teal + " TealInfo au BufNewFile,BufRead *.tli setf tli @@ -1864,6 +1922,9 @@ au BufRead,BufNewFile *.ttl " Terminfo au BufNewFile,BufRead *.ti setf terminfo +" Terraform +au BufRead,BufNewFile *.tfvars setf terraform + " TeX au BufNewFile,BufRead *.latex,*.sty,*.dtx,*.ltx,*.bbl setf tex au BufNewFile,BufRead *.tex call dist#ft#FTtex() @@ -1883,6 +1944,9 @@ au BufNewFile,BufRead .tidyrc,tidyrc,tidy.conf setf tidy " TF mud client au BufNewFile,BufRead *.tf,.tfrc,tfrc setf tf +" TLA+ +au BufRead,BufNewFile *.tla setf tla + " tmux configuration au BufNewFile,BufRead {.,}tmux*.conf setf tmux @@ -2144,6 +2208,9 @@ au BufNewFile,BufRead *.raml setf raml " yum conf (close enough to dosini) au BufNewFile,BufRead */etc/yum.conf setf dosini +" YANG +au BufRead,BufNewFile *.yang setf yang + " Zimbu au BufNewFile,BufRead *.zu setf zimbu " Zimbu Templates diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index 819587bb3e..bd3b44e95b 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -220,26 +220,37 @@ local extension = { ["f08"] = "fortran", fpc = "fpcmake", fsl = "framescript", - bi = "freebasic", fb = "freebasic", fsi = "fsharp", fsx = "fsharp", + fusion = "fusion", gdmo = "gdmo", mo = "gdmo", + tres = "gdresource", + tscn = "gdresource", + gd = "gdscript", ged = "gedcom", gmi = "gemtext", gemini = "gemtext", gift = "gift", + glsl = "glsl", gpi = "gnuplot", + gnuplot = "gnuplot", go = "go", gp = "gp", gs = "grads", + gql = "graphql", + graphql = "graphql", + graphqls = "graphql", gretl = "gretl", gradle = "groovy", groovy = "groovy", gsp = "gsp", + hack = "hack", + hackpartial = "hack", haml = "haml", hsm = "hamster", + hbs = "handlebars", ["hs-boot"] = "haskell", hsig = "haskell", hsc = "haskell", @@ -251,8 +262,11 @@ local extension = { errsum = "hercules", ev = "hercules", vc = "hercules", + hcl = "hcl", + heex = "heex", hex = "hex", ["h32"] = "hex", + hjson = "hjson", hog = "hog", hws = "hollywood", htt = "httest", @@ -293,6 +307,7 @@ local extension = { webmanifest = "json", ipynb = "json", ["json-patch"] = "json", + json5 = "json5", jsonc = "jsonc", jsp = "jsp", jl = "julia", @@ -309,6 +324,9 @@ local extension = { lte = "latte", ld = "ld", ldif = "ldif", + journal = "ledger", + ldg = "ledger", + ledger = "ledger", less = "less", lex = "lex", lxx = "lex", @@ -392,6 +410,7 @@ local extension = { ncf = "ncf", nginx = "nginx", ninja = "ninja", + nix = "nix", nqc = "nqc", roff = "nroff", tmac = "nroff", @@ -426,6 +445,7 @@ local extension = { pcmk = "pcmk", pdf = "pdf", plx = "perl", + prisma = "prisma", psgi = "perl", al = "perl", ctp = "php", @@ -469,6 +489,7 @@ local extension = { ["ps1xml"] = "ps1xml", psf = "psf", psl = "psl", + pug = "pug", arr = "pyret", pxd = "pyrex", pyx = "pyrex", @@ -476,6 +497,8 @@ local extension = { py = "python", pyi = "python", ptl = "python", + ql = "ql", + qll = "ql", rad = "radiance", mat = "radiance", ["pod6"] = "raku", @@ -612,6 +635,7 @@ local extension = { mata = "stata", ado = "stata", stp = "stp", + sface = "surface", svelte = "svelte", svg = "svg", swift = "swift", @@ -625,6 +649,7 @@ local extension = { itcl = "tcl", tk = "tcl", jacl = "tcl", + tl = "teal", tmpl = "template", ti = "terminfo", dtx = "tex", @@ -637,6 +662,8 @@ local extension = { texinfo = "texinfo", text = "text", tf = "tf", + tfvars = "terraform", + tla = "tla", tli = "tli", toml = "toml", tpp = "tpp", @@ -724,6 +751,7 @@ local extension = { yxx = "yacc", yml = "yaml", yaml = "yaml", + yang = "yang", ["z8a"] = "z8a", zig = "zig", zu = "zimbu", @@ -738,7 +766,9 @@ local extension = { PL = function() vim.fn["dist#ft#FTpl"]() end, R = function() vim.fn["dist#ft#FTr"]() end, asm = function() vim.fn["dist#ft#FTasm"]() end, - bas = function() vim.fn["dist#ft#FTVB"]("basic") end, + bas = function() vim.fn["dist#ft#FTbas"]() end, + bi = function() vim.fn["dist#ft#FTbas"]() end, + bm = function() vim.fn["dist#ft#FTbas"]() end, bash = function() vim.fn["dist#ft#SetFileTypeSH"]("bash") end, btm = function() vim.fn["dist#ft#FTbtm"]() end, c = function() vim.fn["dist#ft#FTlpc"]() end, @@ -890,8 +920,6 @@ local filename = { ["EDIT_DESCRIPTION"] = "gitcommit", [".gitconfig"] = "gitconfig", [".gitmodules"] = "gitconfig", - ["/.config/git/config"] = "gitconfig", - ["/etc/gitconfig"] = "gitconfig", ["gitolite.conf"] = "gitolite", ["git-rebase-todo"] = "gitrebase", gkrellmrc = "gkrellmrc", @@ -899,6 +927,7 @@ local filename = { [".gnashpluginrc"] = "gnash", gnashpluginrc = "gnash", gnashrc = "gnash", + ["go.work"] = "gowork", [".gprc"] = "gp", ["/.gnupg/gpg.conf"] = "gpg", ["/.gnupg/options"] = "gpg", @@ -1146,7 +1175,10 @@ local pattern = { [".*Eterm/.*%.cfg"] = "eterm", [".*%.git/modules/.*/config"] = "gitconfig", [".*%.git/config"] = "gitconfig", + [".*/etc/gitconfig"] = "gitconfig", [".*/%.config/git/config"] = "gitconfig", + [".*%.git/config%.worktree"] = "gitconfig", + [".*%.git/worktrees/.*/config%.worktree"] = "gitconfig", ["%.gitsendemail%.msg%......."] = "gitsendemail", ["gkrellmrc_."] = "gkrellmrc", [".*/usr/.*/gnupg/options%.skel"] = "gpg", diff --git a/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim b/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim index 829e41001b..49d9389773 100644 --- a/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim +++ b/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim @@ -2,7 +2,7 @@ " " Author: Bram Moolenaar " Copyright: Vim license applies, see ":help license" -" Last Change: 2022 Jan 13 +" Last Change: 2022 Jan 17 " " WORK IN PROGRESS - Only the basics work " Note: On MS-Windows you need a recent version of gdb. The one included with @@ -1344,6 +1344,7 @@ func s:HandleCursor(msg) if lnum =~ '^[0-9]*$' call s:GotoSourcewinOrCreateIt() if expand('%:p') != fnamemodify(fname, ':p') + echomsg 'different fname: "' .. expand('%:p') .. '" vs "' .. fnamemodify(fname, ':p') .. '"' augroup Termdebug " Always open a file read-only instead of showing the ATTENTION " prompt, since we are unlikely to want to edit the file. diff --git a/runtime/syntax/rc.vim b/runtime/syntax/rc.vim index 4c6856bc83..d69edd00fd 100644 --- a/runtime/syntax/rc.vim +++ b/runtime/syntax/rc.vim @@ -1,7 +1,7 @@ " Vim syntax file " Language: M$ Resource files (*.rc) " Maintainer: Christian Brabandt -" Last Change: 2015-05-29 +" Last Change: 20220116 " Repository: https://github.com/chrisbra/vim-rc-syntax " License: Vim (see :h license) " Previous Maintainer: Heiko Erhardt <Heiko.Erhardt@munich.netsurf.de> @@ -173,16 +173,17 @@ hi def link rcAttribute rcCommonAttribute hi def link rcStdId rcStatement hi def link rcStatement Statement -" Default color overrides -hi def rcLanguage term=reverse ctermbg=Red ctermfg=Yellow guibg=Red guifg=Yellow -hi def rcMainObject term=underline ctermfg=Blue guifg=Blue -hi def rcSubObject ctermfg=Green guifg=Green -hi def rcCaptionParam term=underline ctermfg=DarkGreen guifg=Green -hi def rcParam ctermfg=DarkGreen guifg=DarkGreen -hi def rcStatement ctermfg=DarkGreen guifg=DarkGreen -hi def rcCommonAttribute ctermfg=Brown guifg=Brown +hi def link rcLanguage Constant +hi def link rcCaptionParam Constant +hi def link rcCommonAttribute Constant + +hi def link rcMainObject Identifier +hi def link rcSubObject Define +hi def link rcParam Constant +hi def link rcStatement Statement +" +"hi def link rcIdentifier Identifier -"hi def link rcIdentifier Identifier let b:current_syntax = "rc" diff --git a/runtime/syntax/scala.vim b/runtime/syntax/scala.vim index 16e114778d..c08e60e55a 100644 --- a/runtime/syntax/scala.vim +++ b/runtime/syntax/scala.vim @@ -3,7 +3,7 @@ " Maintainer: Derek Wyatt " URL: https://github.com/derekwyatt/vim-scala " License: Same as Vim -" Last Change: 23 August 2021 +" Last Change: 23 January 2022 " ---------------------------------------------------------------------------- if !exists('main_syntax') @@ -43,55 +43,55 @@ syn keyword scalaKeyword class trait object extends with nextgroup=scalaInstance syn keyword scalaKeyword case nextgroup=scalaKeyword,scalaCaseFollowing skipwhite syn keyword scalaKeyword val nextgroup=scalaNameDefinition,scalaQuasiQuotes skipwhite syn keyword scalaKeyword def var nextgroup=scalaNameDefinition skipwhite -hi link scalaKeyword Keyword +hi def link scalaKeyword Keyword exe 'syn region scalaBlock start=/{/ end=/}/ contains=' . s:ContainedGroup() . ' fold' syn keyword scalaAkkaSpecialWord when goto using startWith initialize onTransition stay become unbecome -hi link scalaAkkaSpecialWord PreProc +hi def link scalaAkkaSpecialWord PreProc syn keyword scalatestSpecialWord shouldBe syn match scalatestShouldDSLA /^\s\+\zsit should/ syn match scalatestShouldDSLB /\<should\>/ -hi link scalatestSpecialWord PreProc -hi link scalatestShouldDSLA PreProc -hi link scalatestShouldDSLB PreProc +hi def link scalatestSpecialWord PreProc +hi def link scalatestShouldDSLA PreProc +hi def link scalatestShouldDSLB PreProc syn match scalaSymbol /'[_A-Za-z0-9$]\+/ -hi link scalaSymbol Number +hi def link scalaSymbol Number syn match scalaChar /'.'/ syn match scalaChar /'\\[\\"'ntbrf]'/ contains=scalaEscapedChar syn match scalaChar /'\\u[A-Fa-f0-9]\{4}'/ contains=scalaUnicodeChar syn match scalaEscapedChar /\\[\\"'ntbrf]/ syn match scalaUnicodeChar /\\u[A-Fa-f0-9]\{4}/ -hi link scalaChar Character -hi link scalaEscapedChar Special -hi link scalaUnicodeChar Special +hi def link scalaChar Character +hi def link scalaEscapedChar Special +hi def link scalaUnicodeChar Special syn match scalaOperator "||" syn match scalaOperator "&&" syn match scalaOperator "|" syn match scalaOperator "&" -hi link scalaOperator Special +hi def link scalaOperator Special syn match scalaNameDefinition /\<[_A-Za-z0-9$]\+\>/ contained nextgroup=scalaPostNameDefinition,scalaVariableDeclarationList syn match scalaNameDefinition /`[^`]\+`/ contained nextgroup=scalaPostNameDefinition syn match scalaVariableDeclarationList /\s*,\s*/ contained nextgroup=scalaNameDefinition syn match scalaPostNameDefinition /\_s*:\_s*/ contained nextgroup=scalaTypeDeclaration -hi link scalaNameDefinition Function +hi def link scalaNameDefinition Function syn match scalaInstanceDeclaration /\<[_\.A-Za-z0-9$]\+\>/ contained nextgroup=scalaInstanceHash syn match scalaInstanceDeclaration /`[^`]\+`/ contained syn match scalaInstanceHash /#/ contained nextgroup=scalaInstanceDeclaration -hi link scalaInstanceDeclaration Special -hi link scalaInstanceHash Type +hi def link scalaInstanceDeclaration Special +hi def link scalaInstanceHash Type syn match scalaUnimplemented /???/ -hi link scalaUnimplemented ERROR +hi def link scalaUnimplemented ERROR syn match scalaCapitalWord /\<[A-Z][A-Za-z0-9$]*\>/ -hi link scalaCapitalWord Special +hi def link scalaCapitalWord Special " Handle type declarations specially syn region scalaTypeStatement matchgroup=Keyword start=/\<type\_s\+\ze/ end=/$/ contains=scalaTypeTypeDeclaration,scalaSquareBrackets,scalaTypeTypeEquals,scalaTypeStatement @@ -105,18 +105,18 @@ syn match scalaTypeTypeEquals /=\ze[^>]/ contained nextgroup=scalaTypeTypePostDe syn match scalaTypeTypeExtension /)\?\_s*\zs\%(⇒\|=>\|<:\|:>\|=:=\|::\|#\)/ contained contains=scalaTypeOperator nextgroup=scalaTypeTypeDeclaration skipwhite syn match scalaTypeTypePostDeclaration /\<[_\.A-Za-z0-9$]\+\>/ contained nextgroup=scalaTypeTypePostExtension skipwhite syn match scalaTypeTypePostExtension /\%(⇒\|=>\|<:\|:>\|=:=\|::\)/ contained contains=scalaTypeOperator nextgroup=scalaTypeTypePostDeclaration skipwhite -hi link scalaTypeTypeDeclaration Type -hi link scalaTypeTypeExtension Keyword -hi link scalaTypeTypePostDeclaration Special -hi link scalaTypeTypePostExtension Keyword +hi def link scalaTypeTypeDeclaration Type +hi def link scalaTypeTypeExtension Keyword +hi def link scalaTypeTypePostDeclaration Special +hi def link scalaTypeTypePostExtension Keyword syn match scalaTypeDeclaration /(/ contained nextgroup=scalaTypeExtension contains=scalaRoundBrackets skipwhite syn match scalaTypeDeclaration /\%(⇒\|=>\)\ze/ contained nextgroup=scalaTypeDeclaration contains=scalaTypeExtension skipwhite syn match scalaTypeDeclaration /\<[_\.A-Za-z0-9$]\+\>/ contained nextgroup=scalaTypeExtension skipwhite syn match scalaTypeExtension /)\?\_s*\zs\%(⇒\|=>\|<:\|:>\|=:=\|::\|#\)/ contained contains=scalaTypeOperator nextgroup=scalaTypeDeclaration skipwhite -hi link scalaTypeDeclaration Type -hi link scalaTypeExtension Keyword -hi link scalaTypePostExtension Keyword +hi def link scalaTypeDeclaration Type +hi def link scalaTypeExtension Keyword +hi def link scalaTypePostExtension Keyword syn match scalaTypeAnnotation /\%([_a-zA-Z0-9$\s]:\_s*\)\ze[_=(\.A-Za-z0-9$]\+/ skipwhite nextgroup=scalaTypeDeclaration contains=scalaRoundBrackets syn match scalaTypeAnnotation /)\_s*:\_s*\ze[_=(\.A-Za-z0-9$]\+/ skipwhite nextgroup=scalaTypeDeclaration @@ -124,51 +124,51 @@ hi clear scalaTypeAnnotation syn match scalaCaseFollowing /\<[_\.A-Za-z0-9$]\+\>/ contained contains=scalaCapitalWord syn match scalaCaseFollowing /`[^`]\+`/ contained contains=scalaCapitalWord -hi link scalaCaseFollowing Special +hi def link scalaCaseFollowing Special syn keyword scalaKeywordModifier abstract override final lazy implicit private protected sealed null super syn keyword scalaSpecialFunction implicitly require -hi link scalaKeywordModifier Function -hi link scalaSpecialFunction Function +hi def link scalaKeywordModifier Function +hi def link scalaSpecialFunction Function syn keyword scalaSpecial this true false ne eq syn keyword scalaSpecial new nextgroup=scalaInstanceDeclaration skipwhite syn match scalaSpecial "\%(=>\|⇒\|<-\|←\|->\|→\)" syn match scalaSpecial /`[^`]\+`/ " Backtick literals -hi link scalaSpecial PreProc +hi def link scalaSpecial PreProc syn keyword scalaExternal package import -hi link scalaExternal Include +hi def link scalaExternal Include syn match scalaStringEmbeddedQuote /\\"/ contained syn region scalaString start=/"/ end=/"/ contains=scalaStringEmbeddedQuote,scalaEscapedChar,scalaUnicodeChar -hi link scalaString String -hi link scalaStringEmbeddedQuote String +hi def link scalaString String +hi def link scalaStringEmbeddedQuote String syn region scalaIString matchgroup=scalaInterpolationBrackets start=/\<[a-zA-Z][a-zA-Z0-9_]*"/ skip=/\\"/ end=/"/ contains=scalaInterpolation,scalaInterpolationB,scalaEscapedChar,scalaUnicodeChar syn region scalaTripleIString matchgroup=scalaInterpolationBrackets start=/\<[a-zA-Z][a-zA-Z0-9_]*"""/ end=/"""\ze\%([^"]\|$\)/ contains=scalaInterpolation,scalaInterpolationB,scalaEscapedChar,scalaUnicodeChar -hi link scalaIString String -hi link scalaTripleIString String +hi def link scalaIString String +hi def link scalaTripleIString String syn match scalaInterpolation /\$[a-zA-Z0-9_$]\+/ contained exe 'syn region scalaInterpolationB matchgroup=scalaInterpolationBoundary start=/\${/ end=/}/ contained contains=' . s:ContainedGroup() -hi link scalaInterpolation Function +hi def link scalaInterpolation Function hi clear scalaInterpolationB syn region scalaFString matchgroup=scalaInterpolationBrackets start=/f"/ skip=/\\"/ end=/"/ contains=scalaFInterpolation,scalaFInterpolationB,scalaEscapedChar,scalaUnicodeChar syn match scalaFInterpolation /\$[a-zA-Z0-9_$]\+\(%[-A-Za-z0-9\.]\+\)\?/ contained exe 'syn region scalaFInterpolationB matchgroup=scalaInterpolationBoundary start=/${/ end=/}\(%[-A-Za-z0-9\.]\+\)\?/ contained contains=' . s:ContainedGroup() -hi link scalaFString String -hi link scalaFInterpolation Function +hi def link scalaFString String +hi def link scalaFInterpolation Function hi clear scalaFInterpolationB syn region scalaTripleString start=/"""/ end=/"""\%([^"]\|$\)/ contains=scalaEscapedChar,scalaUnicodeChar syn region scalaTripleFString matchgroup=scalaInterpolationBrackets start=/f"""/ end=/"""\%([^"]\|$\)/ contains=scalaFInterpolation,scalaFInterpolationB,scalaEscapedChar,scalaUnicodeChar -hi link scalaTripleString String -hi link scalaTripleFString String +hi def link scalaTripleString String +hi def link scalaTripleFString String -hi link scalaInterpolationBrackets Special -hi link scalaInterpolationBoundary Function +hi def link scalaInterpolationBrackets Special +hi def link scalaInterpolationBoundary Function syn match scalaNumber /\<0[dDfFlL]\?\>/ " Just a bare 0 syn match scalaNumber /\<[1-9]\d*[dDfFlL]\?\>/ " A multi-digit number - octal numbers with leading 0's are deprecated in Scala @@ -176,16 +176,16 @@ syn match scalaNumber /\<0[xX][0-9a-fA-F]\+[dDfFlL]\?\>/ " Hex number syn match scalaNumber /\%(\<\d\+\.\d*\|\.\d\+\)\%([eE][-+]\=\d\+\)\=[fFdD]\=/ " exponential notation 1 syn match scalaNumber /\<\d\+[eE][-+]\=\d\+[fFdD]\=\>/ " exponential notation 2 syn match scalaNumber /\<\d\+\%([eE][-+]\=\d\+\)\=[fFdD]\>/ " exponential notation 3 -hi link scalaNumber Number +hi def link scalaNumber Number syn region scalaRoundBrackets start="(" end=")" skipwhite contained contains=scalaTypeDeclaration,scalaSquareBrackets,scalaRoundBrackets syn region scalaSquareBrackets matchgroup=scalaSquareBracketsBrackets start="\[" end="\]" skipwhite nextgroup=scalaTypeExtension contains=scalaTypeDeclaration,scalaSquareBrackets,scalaTypeOperator,scalaTypeAnnotationParameter syn match scalaTypeOperator /[-+=:<>]\+/ contained syn match scalaTypeAnnotationParameter /@\<[`_A-Za-z0-9$]\+\>/ contained -hi link scalaSquareBracketsBrackets Type -hi link scalaTypeOperator Keyword -hi link scalaTypeAnnotationParameter Function +hi def link scalaSquareBracketsBrackets Type +hi def link scalaTypeOperator Keyword +hi def link scalaTypeAnnotationParameter Function syn match scalaShebang "\%^#!.*" display syn region scalaMultilineComment start="/\*" end="\*/" contains=scalaMultilineComment,scalaDocLinks,scalaParameterAnnotation,scalaCommentAnnotation,scalaTodo,scalaCommentCodeBlock,@Spell keepend fold @@ -195,20 +195,20 @@ syn match scalaParamAnnotationValue /[.`_A-Za-z0-9$]\+/ contained syn region scalaDocLinks start="\[\[" end="\]\]" contained syn region scalaCommentCodeBlock matchgroup=Keyword start="{{{" end="}}}" contained syn match scalaTodo "\vTODO|FIXME|XXX" contained -hi link scalaShebang Comment -hi link scalaMultilineComment Comment -hi link scalaDocLinks Function -hi link scalaParameterAnnotation Function -hi link scalaParamAnnotationValue Keyword -hi link scalaCommentAnnotation Function -hi link scalaCommentCodeBlock String -hi link scalaTodo Todo +hi def link scalaShebang Comment +hi def link scalaMultilineComment Comment +hi def link scalaDocLinks Function +hi def link scalaParameterAnnotation Function +hi def link scalaParamAnnotationValue Keyword +hi def link scalaCommentAnnotation Function +hi def link scalaCommentCodeBlock String +hi def link scalaTodo Todo syn match scalaAnnotation /@\<[`_A-Za-z0-9$]\+\>/ -hi link scalaAnnotation PreProc +hi def link scalaAnnotation PreProc syn match scalaTrailingComment "//.*$" contains=scalaTodo,@Spell -hi link scalaTrailingComment Comment +hi def link scalaTrailingComment Comment syn match scalaAkkaFSM /goto([^)]*)\_s\+\<using\>/ contains=scalaAkkaFSMGotoUsing syn match scalaAkkaFSM /stay\_s\+using/ @@ -221,8 +221,8 @@ syn match scalaAkkaFSM /onTermination/ syn match scalaAkkaFSM /whenUnhandled/ syn match scalaAkkaFSMGotoUsing /\<using\>/ syn match scalaAkkaFSMGotoUsing /\<goto\>/ -hi link scalaAkkaFSM PreProc -hi link scalaAkkaFSMGotoUsing PreProc +hi def link scalaAkkaFSM PreProc +hi def link scalaAkkaFSMGotoUsing PreProc let b:current_syntax = 'scala' diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c index 370f7fb47e..80bd88c4ee 100644 --- a/src/nvim/api/extmark.c +++ b/src/nvim/api/extmark.c @@ -115,7 +115,12 @@ static Array extmark_to_array(ExtmarkInfo extmark, bool id, bool add_dict) if (decor->hl_id) { String name = cstr_to_string((const char *)syn_id2name(decor->hl_id)); PUT(dict, "hl_group", STRING_OBJ(name)); + PUT(dict, "hl_eol", BOOLEAN_OBJ(decor->hl_eol)); } + if (decor->hl_mode) { + PUT(dict, "hl_mode", STRING_OBJ(cstr_to_string(hl_mode_str[decor->hl_mode]))); + } + if (kv_size(decor->virt_text)) { Array chunks = ARRAY_DICT_INIT; for (size_t i = 0; i < decor->virt_text.size; i++) { @@ -129,6 +134,36 @@ static Array extmark_to_array(ExtmarkInfo extmark, bool id, bool add_dict) ADD(chunks, ARRAY_OBJ(chunk)); } PUT(dict, "virt_text", ARRAY_OBJ(chunks)); + PUT(dict, "virt_text_hide", BOOLEAN_OBJ(decor->virt_text_hide)); + if (decor->virt_text_pos == kVTWinCol) { + PUT(dict, "virt_text_win_col", INTEGER_OBJ(decor->col)); + } + PUT(dict, "virt_text_pos", + STRING_OBJ(cstr_to_string(virt_text_pos_str[decor->virt_text_pos]))); + } + + if (kv_size(decor->virt_lines)) { + Array all_chunks = ARRAY_DICT_INIT; + bool virt_lines_leftcol = false; + for (size_t i = 0; i < decor->virt_lines.size; i++) { + Array chunks = ARRAY_DICT_INIT; + VirtText *vt = &decor->virt_lines.items[i].line; + virt_lines_leftcol = decor->virt_lines.items[i].left_col; + for (size_t j = 0; j < vt->size; j++) { + Array chunk = ARRAY_DICT_INIT; + VirtTextChunk *vtc = &vt->items[j]; + ADD(chunk, STRING_OBJ(cstr_to_string(vtc->text))); + if (vtc->hl_id > 0) { + ADD(chunk, + STRING_OBJ(cstr_to_string((const char *)syn_id2name(vtc->hl_id)))); + } + ADD(chunks, ARRAY_OBJ(chunk)); + } + ADD(all_chunks, ARRAY_OBJ(chunks)); + } + PUT(dict, "virt_lines", ARRAY_OBJ(all_chunks)); + PUT(dict, "virt_lines_above", BOOLEAN_OBJ(decor->virt_lines_above)); + PUT(dict, "virt_lines_leftcol", BOOLEAN_OBJ(virt_lines_leftcol)); } if (decor->hl_id || kv_size(decor->virt_text)) { diff --git a/src/nvim/api/keysets.lua b/src/nvim/api/keysets.lua index a385cfc64f..7d521bbf25 100644 --- a/src/nvim/api/keysets.lua +++ b/src/nvim/api/keysets.lua @@ -44,6 +44,7 @@ return { "count"; "desc"; "force"; + "keepscript"; "nargs"; "range"; "register"; diff --git a/src/nvim/api/private/converter.c b/src/nvim/api/private/converter.c index e370c0d4d4..3d4ff202fe 100644 --- a/src/nvim/api/private/converter.c +++ b/src/nvim/api/private/converter.c @@ -233,6 +233,7 @@ Object vim_to_object(typval_T *obj) { if (obj->v_type == VAR_FUNC) { ufunc_T *fp = find_func(obj->vval.v_string); + assert(fp != NULL); if (fp->uf_cb == nlua_CFunction_func_call) { LuaRef ref = api_new_luaref(((LuaCFunctionState *)fp->uf_cb_state)->lua_callable.func_ref); return LUAREF_OBJ(ref); diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index f777fa1d27..f540f8f7ee 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -1510,6 +1510,12 @@ void add_user_command(String name, Object command, Dict(user_command) *opts, int goto err; } + if (api_object_to_bool(opts->keepscript, "keepscript", false, err)) { + argt |= EX_KEEPSCRIPT; + } else if (ERROR_SET(err)) { + goto err; + } + bool force = api_object_to_bool(opts->force, "force", true, err); if (ERROR_SET(err)) { goto err; diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 59db12f2c0..7c194935ce 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -187,21 +187,23 @@ static void on_redraw_event(void **argv) /// On execution error: does not fail, but updates v:errmsg. /// /// To input sequences like <C-o> use |nvim_replace_termcodes()| (typically -/// with escape_csi=true) to replace |keycodes|, then pass the result to +/// with escape_ks=false) to replace |keycodes|, then pass the result to /// nvim_feedkeys(). /// /// Example: /// <pre> /// :let key = nvim_replace_termcodes("<C-o>", v:true, v:false, v:true) -/// :call nvim_feedkeys(key, 'n', v:true) +/// :call nvim_feedkeys(key, 'n', v:false) /// </pre> /// /// @param keys to be typed /// @param mode behavior flags, see |feedkeys()| -/// @param escape_csi If true, escape K_SPECIAL/CSI bytes in `keys` +/// @param escape_ks If true, escape K_SPECIAL bytes in `keys` +/// This should be false if you already used +/// |nvim_replace_termcodes()|, and true otherwise. /// @see feedkeys() -/// @see vim_strsave_escape_csi -void nvim_feedkeys(String keys, String mode, Boolean escape_csi) +/// @see vim_strsave_escape_ks +void nvim_feedkeys(String keys, String mode, Boolean escape_ks) FUNC_API_SINCE(1) { bool remap = true; @@ -232,10 +234,10 @@ void nvim_feedkeys(String keys, String mode, Boolean escape_csi) } char *keys_esc; - if (escape_csi) { - // Need to escape K_SPECIAL and CSI before putting the string in the + if (escape_ks) { + // Need to escape K_SPECIAL before putting the string in the // typeahead buffer. - keys_esc = (char *)vim_strsave_escape_csi((char_u *)keys.data); + keys_esc = (char *)vim_strsave_escape_ks((char_u *)keys.data); } else { keys_esc = keys.data; } @@ -245,7 +247,7 @@ void nvim_feedkeys(String keys, String mode, Boolean escape_csi) typebuf_was_filled = true; } - if (escape_csi) { + if (escape_ks) { xfree(keys_esc); } @@ -2281,6 +2283,11 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error * fillchar = ' '; } else { wp = find_window_by_handle(window, err); + + if (wp == NULL) { + api_set_error(err, kErrorTypeException, "unknown winid %d", window); + return result; + } ewp = wp; if (fillchar == 0) { diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index abd22fba26..0248d42f58 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -4351,7 +4351,7 @@ int build_stl_str_hl(win_T *wp, char_u *out, size_t outlen, char_u *fmt, int use // Only free the string buffer if we allocated it. // Note: This is not needed if `str` is pointing at `tmp` if (opt == STL_VIM_EXPR) { - xfree(str); + XFREE_CLEAR(str); } if (num >= 0 || (!itemisflag && str && *str)) { diff --git a/src/nvim/channel.h b/src/nvim/channel.h index 81b75e2d31..50d6b3600a 100644 --- a/src/nvim/channel.h +++ b/src/nvim/channel.h @@ -96,6 +96,8 @@ struct Channel { EXTERN PMap(uint64_t) channels INIT(= MAP_INIT); +EXTERN Callback on_print INIT(= CALLBACK_INIT); + #ifdef INCLUDE_GENERATED_DECLARATIONS # include "channel.h.generated.h" #endif diff --git a/src/nvim/decoration.h b/src/nvim/decoration.h index 209e2176f2..02472d09e4 100644 --- a/src/nvim/decoration.h +++ b/src/nvim/decoration.h @@ -17,6 +17,8 @@ typedef enum { kVTRightAlign, } VirtTextPos; +EXTERN const char *const virt_text_pos_str[] INIT(= { "eol", "overlay", "win_col", "right_align" }); + typedef enum { kHlModeUnknown, kHlModeReplace, @@ -24,6 +26,8 @@ typedef enum { kHlModeBlend, } HlMode; +EXTERN const char *const hl_mode_str[] INIT(= { "", "replace", "combine", "blend" }); + typedef kvec_t(VirtTextChunk) VirtText; #define VIRTTEXT_EMPTY ((VirtText)KV_INITIAL_VALUE) diff --git a/src/nvim/edit.c b/src/nvim/edit.c index 9efe5a27c4..cafc764ddf 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -260,7 +260,7 @@ static colnr_T Insstart_blank_vcol; // vcol for first inserted blank static bool update_Insstart_orig = true; // set Insstart_orig to Insstart static char_u *last_insert = NULL; // the text of the previous insert, - // K_SPECIAL and CSI are escaped + // K_SPECIAL is escaped static int last_insert_skip; // nr of chars in front of previous insert static int new_insert_skip; // nr of chars in front of current insert static int did_restart_edit; // "restart_edit" when calling edit() @@ -663,8 +663,12 @@ static int insert_execute(VimState *state, int key) InsertState *const s = (InsertState *)state; if (stop_insert_mode) { // Insert mode ended, possibly from a callback. + if (key != K_IGNORE && key != K_NOP) { + vungetc(key); + } s->count = 0; s->nomove = true; + ins_compl_prep(ESC); return 0; } @@ -6817,7 +6821,7 @@ void free_last_insert(void) /// Add character "c" to buffer "s" /// -/// Escapes the special meaning of K_SPECIAL and CSI, handles multi-byte +/// Escapes the special meaning of K_SPECIAL, handles multi-byte /// characters. /// /// @param[in] c Character to add. @@ -6831,7 +6835,7 @@ char_u *add_char2buf(int c, char_u *s) const int len = utf_char2bytes(c, temp); for (int i = 0; i < len; i++) { c = temp[i]; - // Need to escape K_SPECIAL and CSI like in the typeahead buffer. + // Need to escape K_SPECIAL like in the typeahead buffer. if (c == K_SPECIAL) { *s++ = K_SPECIAL; *s++ = KS_SPECIAL; diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 7701688b49..4a07f6a850 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -10215,6 +10215,10 @@ static void f_stdioopen(typval_T *argvars, typval_T *rettv, FunPtr fptr) if (!tv_dict_get_callback(opts, S_LEN("on_stdin"), &on_stdin.cb)) { return; } + if (!tv_dict_get_callback(opts, S_LEN("on_print"), &on_print)) { + return; + } + on_stdin.buffered = tv_dict_get_number(opts, "stdin_buffered"); if (on_stdin.buffered && on_stdin.cb.type == kCallbackNone) { on_stdin.self = opts; diff --git a/src/nvim/eval/typval.h b/src/nvim/eval/typval.h index d1275d6512..ad01c01499 100644 --- a/src/nvim/eval/typval.h +++ b/src/nvim/eval/typval.h @@ -81,7 +81,8 @@ typedef struct { } data; CallbackType type; } Callback; -#define CALLBACK_NONE ((Callback){ .type = kCallbackNone }) +#define CALLBACK_INIT { .type = kCallbackNone } +#define CALLBACK_NONE ((Callback)CALLBACK_INIT) /// Structure holding dictionary watcher typedef struct dict_watcher { diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index 95390b1a70..ca5e14ee63 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -1099,6 +1099,9 @@ void ex_copy(linenr_T line1, linenr_T line2, linenr_T n) } appended_lines_mark(n, count); + if (VIsual_active) { + check_pos(curbuf, &VIsual); + } msgmore((long)count); } diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c index 2e8d39ec30..267f5616f5 100644 --- a/src/nvim/ex_cmds2.c +++ b/src/nvim/ex_cmds2.c @@ -1613,7 +1613,7 @@ void ex_compiler(exarg_T *eap) if (old_cur_comp != NULL) { old_cur_comp = vim_strsave(old_cur_comp); } - do_cmdline_cmd("command -nargs=* CompilerSet setlocal <args>"); + do_cmdline_cmd("command -nargs=* -keepscript CompilerSet setlocal <args>"); } do_unlet(S_LEN("g:current_compiler"), true); do_unlet(S_LEN("b:current_compiler"), true); diff --git a/src/nvim/ex_cmds_defs.h b/src/nvim/ex_cmds_defs.h index e5eab61f9e..eaf5f627b6 100644 --- a/src/nvim/ex_cmds_defs.h +++ b/src/nvim/ex_cmds_defs.h @@ -61,6 +61,7 @@ // current buffer is locked #define EX_MODIFY 0x100000 // forbidden in non-'modifiable' buffer #define EX_FLAGS 0x200000 // allow flags after count in argument +#define EX_KEEPSCRIPT 0x4000000 // keep sctx of where command was invoked #define EX_FILES (EX_XFILE | EX_EXTRA) // multiple extra files allowed #define EX_FILE1 (EX_FILES | EX_NOSPC) // 1 file, defaults to current file #define EX_WORD1 (EX_EXTRA | EX_NOSPC) // one extra word allowed diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index b33a17c631..a4b43e598d 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -5517,6 +5517,8 @@ static int uc_scan_attr(char_u *attr, size_t len, uint32_t *argt, long *def, int *flags |= UC_BUFFER; } else if (STRNICMP(attr, "register", len) == 0) { *argt |= EX_REGSTR; + } else if (STRNICMP(attr, "keepscript", len) == 0) { + *argt |= EX_KEEPSCRIPT; } else if (STRNICMP(attr, "bar", len) == 0) { *argt |= EX_TRLBAR; } else { @@ -6204,7 +6206,6 @@ static void do_ucmd(exarg_T *eap) // K_SPECIAL has been put in the buffer as K_SPECIAL // KS_SPECIAL KE_FILLER, like for mappings, but // do_cmdline() doesn't handle that, so convert it back. - // Also change K_SPECIAL KS_EXTRA KE_CSI into CSI. len = ksp - p; if (len > 0) { memmove(q, p, len); @@ -6257,10 +6258,14 @@ static void do_ucmd(exarg_T *eap) buf = xmalloc(totlen + 1); } - current_sctx.sc_sid = cmd->uc_script_ctx.sc_sid; + if ((cmd->uc_argt & EX_KEEPSCRIPT) == 0) { + current_sctx.sc_sid = cmd->uc_script_ctx.sc_sid; + } (void)do_cmdline(buf, eap->getline, eap->cookie, DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_KEYTYPED); - current_sctx = save_current_sctx; + if ((cmd->uc_argt & EX_KEEPSCRIPT) == 0) { + current_sctx = save_current_sctx; + } xfree(buf); xfree(split_buf); } @@ -6306,7 +6311,7 @@ char_u *get_user_cmd_flags(expand_T *xp, int idx) { static char *user_cmd_flags[] = { "addr", "bang", "bar", "buffer", "complete", "count", - "nargs", "range", "register" }; + "nargs", "range", "register", "keepscript" }; if (idx >= (int)ARRAY_SIZE(user_cmd_flags)) { return NULL; @@ -8627,7 +8632,7 @@ static void ex_normal(exarg_T *eap) return; } - // vgetc() expects a CSI and K_SPECIAL to have been escaped. Don't do + // vgetc() expects K_SPECIAL to have been escaped. Don't do // this for the K_SPECIAL leading byte, otherwise special keys will not // work. { @@ -8636,8 +8641,7 @@ static void ex_normal(exarg_T *eap) // Count the number of characters to be escaped. for (p = eap->arg; *p != NUL; p++) { for (l = utfc_ptr2len(p) - 1; l > 0; l--) { - if (*++p == K_SPECIAL // trailbyte K_SPECIAL or CSI - ) { + if (*++p == K_SPECIAL) { // trailbyte K_SPECIAL len += 2; } } @@ -9846,6 +9850,7 @@ Dictionary commands_array(buf_T *buf) PUT(d, "bang", BOOLEAN_OBJ(!!(cmd->uc_argt & EX_BANG))); PUT(d, "bar", BOOLEAN_OBJ(!!(cmd->uc_argt & EX_TRLBAR))); PUT(d, "register", BOOLEAN_OBJ(!!(cmd->uc_argt & EX_REGSTR))); + PUT(d, "keepscript", BOOLEAN_OBJ(!!(cmd->uc_argt & EX_KEEPSCRIPT))); switch (cmd->uc_argt & (EX_EXTRA | EX_NOSPC | EX_NEEDARG)) { case 0: diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 78b8e43e65..fd75cfc7f8 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -772,7 +772,7 @@ static uint8_t *command_line_enter(int firstc, long count, int indent) ccline.cmdindent = (s->firstc > 0 ? s->indent : 0); // alloc initial ccline.cmdbuff - alloc_cmdbuff(exmode_active ? 250 : s->indent + 1); + alloc_cmdbuff(indent + 50); ccline.cmdlen = ccline.cmdpos = 0; ccline.cmdbuff[0] = NUL; diff --git a/src/nvim/file_search.c b/src/nvim/file_search.c index b2cd5c510b..b4becb3066 100644 --- a/src/nvim/file_search.c +++ b/src/nvim/file_search.c @@ -1433,7 +1433,11 @@ char_u *find_file_in_path_option(char_u *ptr, size_t len, int options, int first rel_fname = NULL; } - if (first == TRUE) { + if (first == true) { + if (len == 0) { + return NULL; + } + // copy file name into NameBuff, expanding environment variables save_char = ptr[len]; ptr[len] = NUL; diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index 5565e17597..ef590adb3a 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -59,25 +59,18 @@ static int curscript = 0; FileDescriptor *scriptin[NSCRIPT] = { NULL }; -/* - * These buffers are used for storing: - * - stuffed characters: A command that is translated into another command. - * - redo characters: will redo the last change. - * - recorded characters: for the "q" command. - * - * The bytes are stored like in the typeahead buffer: - * - K_SPECIAL introduces a special key (two more bytes follow). A literal - * K_SPECIAL is stored as K_SPECIAL KS_SPECIAL KE_FILLER. - * - CSI introduces a GUI termcap code (also when gui.in_use is FALSE, - * otherwise switching the GUI on would make mappings invalid). - * A literal CSI is stored as CSI KS_EXTRA KE_CSI. - * These translations are also done on multi-byte characters! - * - * Escaping CSI bytes is done by the system-specific input functions, called - * by ui_inchar(). - * Escaping K_SPECIAL is done by inchar(). - * Un-escaping is done by vgetc(). - */ +// These buffers are used for storing: +// - stuffed characters: A command that is translated into another command. +// - redo characters: will redo the last change. +// - recorded characters: for the "q" command. +// +// The bytes are stored like in the typeahead buffer: +// - K_SPECIAL introduces a special key (two more bytes follow). A literal +// K_SPECIAL is stored as K_SPECIAL KS_SPECIAL KE_FILLER. +// These translations are also done on multi-byte characters! +// +// Escaping K_SPECIAL is done by inchar(). +// Un-escaping is done by vgetc(). #define MINIMAL_SIZE 20 // minimal size for b_str @@ -173,7 +166,7 @@ void free_buff(buffheader_T *buf) } /// Return the contents of a buffer as a single string. -/// K_SPECIAL and CSI in the returned string are escaped. +/// K_SPECIAL in the returned string is escaped. /// /// @param dozero count == zero is not an error static char_u *get_buffcont(buffheader_T *buffer, int dozero) @@ -202,11 +195,9 @@ static char_u *get_buffcont(buffheader_T *buffer, int dozero) return p; } -/* - * Return the contents of the record buffer as a single string - * and clear the record buffer. - * K_SPECIAL and CSI in the returned string are escaped. - */ +/// Return the contents of the record buffer as a single string +/// and clear the record buffer. +/// K_SPECIAL in the returned string is escaped. char_u *get_recorded(void) { char_u *p; @@ -236,10 +227,8 @@ char_u *get_recorded(void) return p; } -/* - * Return the contents of the redo buffer as a single string. - * K_SPECIAL and CSI in the returned string are escaped. - */ +/// Return the contents of the redo buffer as a single string. +/// K_SPECIAL in the returned string is escaped. char_u *get_inserted(void) { return get_buffcont(&redobuff, FALSE); @@ -247,7 +236,7 @@ char_u *get_inserted(void) /// Add string after the current block of the given buffer /// -/// K_SPECIAL and CSI should have been escaped already. +/// K_SPECIAL should have been escaped already. /// /// @param[out] buf Buffer to add to. /// @param[in] s String to add. @@ -305,10 +294,8 @@ static void add_num_buff(buffheader_T *buf, long n) add_buff(buf, number, -1L); } -/* - * Add character 'c' to buffer "buf". - * Translates special keys, NUL, CSI, K_SPECIAL and multibyte characters. - */ +/// Add character 'c' to buffer "buf". +/// Translates special keys, NUL, K_SPECIAL and multibyte characters. static void add_char_buff(buffheader_T *buf, int c) { uint8_t bytes[MB_MAXBYTES + 1]; @@ -340,12 +327,10 @@ static void add_char_buff(buffheader_T *buf, int c) } } -/* - * Get one byte from the read buffers. Use readbuf1 one first, use readbuf2 - * if that one is empty. - * If advance == TRUE go to the next char. - * No translation is done K_SPECIAL and CSI are escaped. - */ +/// Get one byte from the read buffers. Use readbuf1 one first, use readbuf2 +/// if that one is empty. +/// If advance == TRUE go to the next char. +/// No translation is done K_SPECIAL is escaped. static int read_readbuffers(int advance) { int c; @@ -524,10 +509,8 @@ void restoreRedobuff(save_redo_T *save_redo) old_redobuff = save_redo->sr_old_redobuff; } -/* - * Append "s" to the redo buffer. - * K_SPECIAL and CSI should already have been escaped. - */ +/// Append "s" to the redo buffer. +/// K_SPECIAL should already have been escaped. void AppendToRedobuff(const char *s) { if (!block_redo) { @@ -536,7 +519,7 @@ void AppendToRedobuff(const char *s) } /// Append to Redo buffer literally, escaping special characters with CTRL-V. -/// K_SPECIAL and CSI are escaped as well. +/// K_SPECIAL is escaped as well. /// /// @param str String to append /// @param len Length of `str` or -1 for up to the NUL. @@ -584,10 +567,8 @@ void AppendToRedobuffLit(const char_u *str, int len) } } -/* - * Append a character to the redo buffer. - * Translates special keys, NUL, CSI, K_SPECIAL and multibyte characters. - */ +/// Append a character to the redo buffer. +/// Translates special keys, NUL, K_SPECIAL and multibyte characters. void AppendCharToRedobuff(int c) { if (!block_redo) { @@ -605,17 +586,15 @@ void AppendNumberToRedobuff(long n) } } -/* - * Append string "s" to the stuff buffer. - * CSI and K_SPECIAL must already have been escaped. - */ +/// Append string "s" to the stuff buffer. +/// K_SPECIAL must already have been escaped. void stuffReadbuff(const char *s) { add_buff(&readbuf1, s, -1L); } /// Append string "s" to the redo stuff buffer. -/// @remark CSI and K_SPECIAL must already have been escaped. +/// @remark K_SPECIAL must already have been escaped. void stuffRedoReadbuff(const char *s) { add_buff(&readbuf2, s, -1L); @@ -626,11 +605,9 @@ void stuffReadbuffLen(const char *s, long len) add_buff(&readbuf1, s, len); } -/* - * Stuff "s" into the stuff buffer, leaving special key codes unmodified and - * escaping other K_SPECIAL and CSI bytes. - * Change CR, LF and ESC into a space. - */ +/// Stuff "s" into the stuff buffer, leaving special key codes unmodified and +/// escaping other K_SPECIAL bytes. +/// Change CR, LF and ESC into a space. void stuffReadbuffSpec(const char *s) { while (*s != NUL) { @@ -648,10 +625,8 @@ void stuffReadbuffSpec(const char *s) } } -/* - * Append a character to the stuff buffer. - * Translates special keys, NUL, CSI, K_SPECIAL and multibyte characters. - */ +/// Append a character to the stuff buffer. +/// Translates special keys, NUL, K_SPECIAL and multibyte characters. void stuffcharReadbuff(int c) { add_char_buff(&readbuf1, c); @@ -665,12 +640,12 @@ void stuffnumReadbuff(long n) add_num_buff(&readbuf1, n); } -// Read a character from the redo buffer. Translates K_SPECIAL, CSI and -// multibyte characters. -// The redo buffer is left as it is. -// If init is true, prepare for redo, return FAIL if nothing to redo, OK -// otherwise. -// If old_redo is true, use old_redobuff instead of redobuff. +/// Read a character from the redo buffer. Translates K_SPECIAL and +/// multibyte characters. +/// The redo buffer is left as it is. +/// If init is true, prepare for redo, return FAIL if nothing to redo, OK +/// otherwise. +/// If old_redo is true, use old_redobuff instead of redobuff. static int read_redo(bool init, bool old_redo) { static buffblock_T *bp; @@ -724,9 +699,9 @@ static int read_redo(bool init, bool old_redo) return c; } -// Copy the rest of the redo buffer into the stuff buffer (in a slow way). -// If old_redo is true, use old_redobuff instead of redobuff. -// The escaped K_SPECIAL and CSI are copied without translation. +/// Copy the rest of the redo buffer into the stuff buffer (in a slow way). +/// If old_redo is true, use old_redobuff instead of redobuff. +/// The escaped K_SPECIAL is copied without translation. static void copy_redo(bool old_redo) { int c; @@ -998,28 +973,35 @@ int ins_typebuf(char_u *str, int noremap, int offset, bool nottyped, bool silent * Uses cmd_silent, KeyTyped and KeyNoremap to restore the flags belonging to * the char. */ -void ins_char_typebuf(int c) +void ins_char_typebuf(int c, int modifier) { - char_u buf[MB_MAXBYTES + 1]; - if (IS_SPECIAL(c)) { + char_u buf[MB_MAXBYTES + 4]; + int idx = 0; + if (modifier != 0) { buf[0] = K_SPECIAL; - buf[1] = (char_u)K_SECOND(c); - buf[2] = (char_u)K_THIRD(c); + buf[1] = KS_MODIFIER; + buf[2] = (char_u)modifier; buf[3] = NUL; + idx = 3; + } + if (IS_SPECIAL(c)) { + buf[idx] = K_SPECIAL; + buf[idx + 1] = (char_u)K_SECOND(c); + buf[idx + 2] = (char_u)K_THIRD(c); + buf[idx + 3] = NUL; } else { - buf[utf_char2bytes(c, buf)] = NUL; - char_u *p = buf; - while (*p) { - if ((uint8_t)(*p) == CSI || (uint8_t)(*p) == K_SPECIAL) { - bool is_csi = (uint8_t)(*p) == CSI; - memmove(p + 3, p + 1, STRLEN(p + 1) + 1); + char_u *p = buf + idx; + int char_len = utf_char2bytes(c, p); + // If the character contains K_SPECIAL bytes they need escaping. + for (int i = char_len; --i >= 0; p++) { + if ((uint8_t)(*p) == K_SPECIAL) { + memmove(p + 3, p + 1, (size_t)i); *p++ = K_SPECIAL; - *p++ = is_csi ? KS_EXTRA : KS_SPECIAL; - *p++ = is_csi ? KE_CSI : KE_FILLER; - } else { - p++; + *p++ = KS_SPECIAL; + *p = KE_FILLER; } } + *p = NUL; } (void)ins_typebuf(buf, KeyNoremap, 0, !KeyTyped, cmd_silent); } @@ -1427,15 +1409,13 @@ static void updatescript(int c) } } -/* - * Get the next input character. - * Can return a special key or a multi-byte character. - * Can return NUL when called recursively, use safe_vgetc() if that's not - * wanted. - * This translates escaped K_SPECIAL and CSI bytes to a K_SPECIAL or CSI byte. - * Collects the bytes of a multibyte character into the whole character. - * Returns the modifiers in the global "mod_mask". - */ +/// Get the next input character. +/// Can return a special key or a multi-byte character. +/// Can return NUL when called recursively, use safe_vgetc() if that's not +/// wanted. +/// This translates escaped K_SPECIAL bytes to a K_SPECIAL byte. +/// Collects the bytes of a multibyte character into the whole character. +/// Returns the modifiers in the global "mod_mask". int vgetc(void) { int c, c2; @@ -1461,8 +1441,9 @@ int vgetc(void) mouse_row = old_mouse_row; mouse_col = old_mouse_col; } else { - mod_mask = 0x0; + mod_mask = 0; last_recorded_len = 0; + for (;;) { // this is done twice if there are modifiers bool did_inc = false; if (mod_mask) { // no mapping after modifier has been read @@ -1572,14 +1553,9 @@ int vgetc(void) buf[i] = (char_u)vgetorpeek(true); if (buf[i] == K_SPECIAL) { // Must be a K_SPECIAL - KS_SPECIAL - KE_FILLER sequence, - // which represents a K_SPECIAL (0x80), - // or a CSI - KS_EXTRA - KE_CSI sequence, which represents - // a CSI (0x9B), - // of a K_SPECIAL - KS_EXTRA - KE_CSI, which is CSI too. - c = vgetorpeek(true); - if (vgetorpeek(true) == KE_CSI && c == KS_EXTRA) { - buf[i] = CSI; - } + // which represents a K_SPECIAL (0x80). + (void)vgetorpeek(true); // skip KS_SPECIAL + (void)vgetorpeek(true); // skip KE_FILLER } } no_mapping--; @@ -1593,8 +1569,8 @@ int vgetc(void) if (!no_mapping && KeyTyped && !(State & TERM_FOCUS) && (mod_mask == MOD_MASK_ALT || mod_mask == MOD_MASK_META)) { mod_mask = 0; - ins_char_typebuf(c); - ins_char_typebuf(ESC); + ins_char_typebuf(c, 0); + ins_char_typebuf(ESC, 0); continue; } @@ -2043,7 +2019,7 @@ void vungetc(int c) /// /// When `no_mapping` (global) is zero, checks for mappings in the current mode. /// Only returns one byte (of a multi-byte character). -/// K_SPECIAL and CSI may be escaped, need to get two more bytes then. +/// K_SPECIAL may be escaped, need to get two more bytes then. static int vgetorpeek(bool advance) { int c, c1; @@ -2573,7 +2549,7 @@ int fix_input_buffer(char_u *buf, int len) FUNC_ATTR_NONNULL_ALL { if (!using_script()) { - // Should not escape K_SPECIAL/CSI reading input from the user because vim + // Should not escape K_SPECIAL reading input from the user because vim // key codes keys are processed in input.c/input_enqueue. buf[len] = NUL; return len; @@ -2584,9 +2560,8 @@ int fix_input_buffer(char_u *buf, int len) char_u *p = buf; // Two characters are special: NUL and K_SPECIAL. - // Replace NUL by K_SPECIAL KS_ZERO KE_FILLER + // Replace NUL by K_SPECIAL KS_ZERO KE_FILLER // Replace K_SPECIAL by K_SPECIAL KS_SPECIAL KE_FILLER - // Replace CSI by K_SPECIAL KS_EXTRA KE_CSI for (i = len; --i >= 0; ++p) { if (p[0] == NUL || (p[0] == K_SPECIAL @@ -3477,10 +3452,10 @@ static void showmap(mapblock_T *mp, bool local) } else if (mp->m_str == NULL) { msg_puts_attr("<Nop>", HL_ATTR(HLF_8)); } else { - // Remove escaping of CSI, because "m_str" is in a format to be used + // Remove escaping of K_SPECIAL, because "m_str" is in a format to be used // as typeahead. char_u *s = vim_strsave(mp->m_str); - vim_unescape_csi(s); + vim_unescape_ks(s); msg_outtrans_special(s, false, 0); xfree(s); } @@ -3860,9 +3835,9 @@ bool check_abbr(int c, char_u *ptr, int col, int mincol) int match; if (strchr((const char *)mp->m_keys, K_SPECIAL) != NULL) { - // Might have CSI escaped mp->m_keys. + // Might have K_SPECIAL escaped mp->m_keys. q = vim_strsave(mp->m_keys); - vim_unescape_csi(q); + vim_unescape_ks(q); qlen = (int)STRLEN(q); } // find entries with right mode and keys @@ -3908,7 +3883,7 @@ bool check_abbr(int c, char_u *ptr, int col, int mincol) int newlen = utf_char2bytes(c, tb + j); tb[j + newlen] = NUL; // Need to escape K_SPECIAL. - char_u *escaped = vim_strsave_escape_csi(tb + j); + char_u *escaped = vim_strsave_escape_ks(tb + j); if (escaped != NULL) { newlen = (int)STRLEN(escaped); memmove(tb + j, escaped, (size_t)newlen); @@ -3961,11 +3936,11 @@ static char_u *eval_map_expr(mapblock_T *mp, int c) int save_msg_col; int save_msg_row; - /* Remove escaping of CSI, because "str" is in a format to be used as - * typeahead. */ + // Remove escaping of K_SPECIAL, because "str" is in a format to be used as + // typeahead. if (mp->m_luaref == LUA_NOREF) { expr = vim_strsave(mp->m_str); - vim_unescape_csi(expr); + vim_unescape_ks(expr); } save_cmd = save_cmdline_alloc(); @@ -4005,18 +3980,16 @@ static char_u *eval_map_expr(mapblock_T *mp, int c) if (p == NULL) { return NULL; } - // Escape CSI in the result to be able to use the string as typeahead. - res = vim_strsave_escape_csi(p); + // Escape K_SPECIAL in the result to be able to use the string as typeahead. + res = vim_strsave_escape_ks(p); xfree(p); return res; } -/* - * Copy "p" to allocated memory, escaping K_SPECIAL and CSI so that the result - * can be put in the typeahead buffer. - */ -char_u *vim_strsave_escape_csi(char_u *p) +/// Copy "p" to allocated memory, escaping K_SPECIAL so that the result +/// can be put in the typeahead buffer. +char_u *vim_strsave_escape_ks(char_u *p) { // Need a buffer to hold up to three times as much. Four in case of an // illegal utf-8 byte: @@ -4031,7 +4004,7 @@ char_u *vim_strsave_escape_csi(char_u *p) *d++ = *s++; } else { // Add character, possibly multi-byte to destination, escaping - // CSI and K_SPECIAL. Be careful, it can be an illegal byte! + // K_SPECIAL. Be careful, it can be an illegal byte! d = add_char2buf(utf_ptr2char(s), d); s += utf_ptr2len(s); } @@ -4041,11 +4014,9 @@ char_u *vim_strsave_escape_csi(char_u *p) return res; } -/* - * Remove escaping from CSI and K_SPECIAL characters. Reverse of - * vim_strsave_escape_csi(). Works in-place. - */ -void vim_unescape_csi(char_u *p) +/// Remove escaping from K_SPECIAL characters. Reverse of +/// vim_strsave_escape_ks(). Works in-place. +void vim_unescape_ks(char_u *p) { char_u *s = p, *d = p; @@ -4053,10 +4024,6 @@ void vim_unescape_csi(char_u *p) if (s[0] == K_SPECIAL && s[1] == KS_SPECIAL && s[2] == KE_FILLER) { *d++ = K_SPECIAL; s += 3; - } else if ((s[0] == K_SPECIAL || s[0] == CSI) - && s[1] == KS_EXTRA && s[2] == (int)KE_CSI) { - *d++ = CSI; - s += 3; } else { *d++ = *s++; } @@ -4299,7 +4266,7 @@ int put_escstr(FILE *fd, char_u *strstart, int what) for (; *str != NUL; str++) { // Check for a multi-byte character, which may contain escaped - // K_SPECIAL and CSI bytes. + // K_SPECIAL bytes. const char *p = mb_unescape((const char **)&str); if (p != NULL) { while (*p != NUL) { diff --git a/src/nvim/globals.h b/src/nvim/globals.h index 40c61d01b5..31a09b3969 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -127,7 +127,7 @@ typedef off_t off_T; // When vgetc() is called, it sets mod_mask to the set of modifiers that are // held down based on the MOD_MASK_* symbols that are read first. -EXTERN int mod_mask INIT(= 0x0); // current key modifiers +EXTERN int mod_mask INIT(= 0); // current key modifiers // Cmdline_row is the row where the command line starts, just below the diff --git a/src/nvim/input.c b/src/nvim/input.c index 2f7c5c2c16..5fa9b8b343 100644 --- a/src/nvim/input.c +++ b/src/nvim/input.c @@ -105,7 +105,7 @@ int get_keystroke(MultiQueue *events) // terminal code to complete. n = os_inchar(buf + len, maxlen, len == 0 ? -1L : 100L, 0, events); if (n > 0) { - // Replace zero and CSI by a special key code. + // Replace zero and K_SPECIAL by a special key code. n = fix_input_buffer(buf + len, n); len += n; waited = 0; diff --git a/src/nvim/keymap.c b/src/nvim/keymap.c index abf016b832..32f2158d7b 100644 --- a/src/nvim/keymap.c +++ b/src/nvim/keymap.c @@ -158,7 +158,6 @@ static const struct key_name_entry { { ESC, "Esc" }, { ESC, "Escape" }, // Alternative name { CSI, "CSI" }, - { K_CSI, "xCSI" }, { '|', "Bar" }, { '\\', "Bslash" }, { K_DEL, "Del" }, @@ -964,7 +963,6 @@ char_u *replace_termcodes(const char_u *from, const size_t from_len, char_u **bu for (i = utfc_ptr2len_len(src, (int)(end - src) + 1); i > 0; i--) { // If the character is K_SPECIAL, replace it with K_SPECIAL // KS_SPECIAL KE_FILLER. - // If compiled with the GUI replace CSI with K_CSI. if (*src == K_SPECIAL) { result[dlen++] = K_SPECIAL; result[dlen++] = KS_SPECIAL; diff --git a/src/nvim/keymap.h b/src/nvim/keymap.h index 5a74d1dc00..42cae0c35e 100644 --- a/src/nvim/keymap.h +++ b/src/nvim/keymap.h @@ -220,7 +220,7 @@ enum key_extra { KE_KINS = 79, // keypad Insert key KE_KDEL = 80, // keypad Delete key - KE_CSI = 81, // CSI typed directly + // KE_CSI = 81, // Nvim doesn't need escaping CSI KE_SNR = 82, // <SNR> KE_PLUG = 83, // <Plug> KE_CMDWIN = 84, // open command-line window from Command-line Mode @@ -435,7 +435,6 @@ enum key_extra { #define K_MOUSELEFT TERMCAP2KEY(KS_EXTRA, KE_MOUSELEFT) #define K_MOUSERIGHT TERMCAP2KEY(KS_EXTRA, KE_MOUSERIGHT) -#define K_CSI TERMCAP2KEY(KS_EXTRA, KE_CSI) #define K_SNR TERMCAP2KEY(KS_EXTRA, KE_SNR) #define K_PLUG TERMCAP2KEY(KS_EXTRA, KE_PLUG) #define K_CMDWIN TERMCAP2KEY(KS_EXTRA, KE_CMDWIN) diff --git a/src/nvim/lua/converter.c b/src/nvim/lua/converter.c index f9a2533d4e..0fbd56ed53 100644 --- a/src/nvim/lua/converter.c +++ b/src/nvim/lua/converter.c @@ -619,6 +619,7 @@ bool nlua_push_typval(lua_State *lstate, typval_T *const tv, bool special) } if (tv->v_type == VAR_FUNC) { ufunc_T *fp = find_func(tv->vval.v_string); + assert(fp != NULL); if (fp->uf_cb == nlua_CFunction_func_call) { nlua_pushref(lstate, ((LuaCFunctionState *)fp->uf_cb_state)->lua_callable.func_ref); return true; diff --git a/src/nvim/mbyte.c b/src/nvim/mbyte.c index 5eb209a6f6..1d1cd5e271 100644 --- a/src/nvim/mbyte.c +++ b/src/nvim/mbyte.c @@ -2089,8 +2089,7 @@ const char *mb_unescape(const char **const pp) size_t buf_idx = 0; uint8_t *str = (uint8_t *)(*pp); - // Must translate K_SPECIAL KS_SPECIAL KE_FILLER to K_SPECIAL and CSI - // KS_EXTRA KE_CSI to CSI. + // Must translate K_SPECIAL KS_SPECIAL KE_FILLER to K_SPECIAL. // Maximum length of a utf-8 character is 4 bytes. for (size_t str_idx = 0; str[str_idx] != NUL && buf_idx < 4; str_idx++) { if (str[str_idx] == K_SPECIAL @@ -2098,11 +2097,6 @@ const char *mb_unescape(const char **const pp) && str[str_idx + 2] == KE_FILLER) { buf[buf_idx++] = (char)K_SPECIAL; str_idx += 2; - } else if ((str[str_idx] == K_SPECIAL) - && str[str_idx + 1] == KS_EXTRA - && str[str_idx + 2] == KE_CSI) { - buf[buf_idx++] = (char)CSI; - str_idx += 2; } else if (str[str_idx] == K_SPECIAL) { break; // A special key can't be a multibyte char. } else { diff --git a/src/nvim/message.c b/src/nvim/message.c index 39b023132e..e1e253cd2e 100644 --- a/src/nvim/message.c +++ b/src/nvim/message.c @@ -1215,7 +1215,7 @@ void wait_return(int redraw) } else if (vim_strchr((char_u *)"\r\n ", c) == NULL && c != Ctrl_C) { // Put the character back in the typeahead buffer. Don't use the // stuff buffer, because lmaps wouldn't work. - ins_char_typebuf(c); + ins_char_typebuf(c, mod_mask); do_redraw = true; // need a redraw even though there is // typeahead } @@ -2647,6 +2647,17 @@ static void msg_puts_printf(const char *str, const ptrdiff_t maxlen) char buf[7]; char *p; + if (on_print.type != kCallbackNone) { + typval_T argv[1]; + argv[0].v_type = VAR_STRING; + argv[0].v_lock = VAR_UNLOCKED; + argv[0].vval.v_string = (char_u *)str; + typval_T rettv = TV_INITIAL_VALUE; + callback_call(&on_print, 1, argv, &rettv); + tv_clear(&rettv); + return; + } + while ((maxlen < 0 || s - str < maxlen) && *s != NUL) { int len = utf_ptr2len((const char_u *)s); if (!(silent_mode && p_verbose == 0)) { @@ -3497,7 +3508,7 @@ int do_dialog(int type, char_u *title, char_u *message, char_u *buttons, int dfl } if (c == ':' && ex_cmd) { retval = dfltbutton; - ins_char_typebuf(':'); + ins_char_typebuf(':', 0); break; } diff --git a/src/nvim/normal.c b/src/nvim/normal.c index 2b5b47c0b3..63311160a7 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -1010,7 +1010,7 @@ static int normal_execute(VimState *state, int key) // restart automatically. // Insert the typed character in the typeahead buffer, so that it can // be mapped in Insert mode. Required for ":lmap" to work. - ins_char_typebuf(s->c); + ins_char_typebuf(s->c, mod_mask); if (restart_edit != 0) { s->c = 'd'; } else { @@ -4472,8 +4472,13 @@ bool get_visual_text(cmdarg_T *cap, char_u **pp, size_t *lenp) *pp = ml_get_pos(&VIsual); *lenp = (size_t)curwin->w_cursor.col - (size_t)VIsual.col + 1; } - // Correct the length to include the whole last character. - *lenp += (size_t)(utfc_ptr2len(*pp + (*lenp - 1)) - 1); + if (**pp == NUL) { + *lenp = 0; + } + if (*lenp > 0) { + // Correct the length to include all bytes of the last character. + *lenp += (size_t)(utfc_ptr2len(*pp + (*lenp - 1)) - 1); + } } reset_VIsual_and_resel(); return true; @@ -5963,11 +5968,8 @@ static void nv_visual(cmdarg_T *cap) * was only one -- webb */ if (resel_VIsual_mode != 'v' || resel_VIsual_line_count > 1) { - curwin->w_cursor.lnum += - resel_VIsual_line_count * cap->count0 - 1; - if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count) { - curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count; - } + curwin->w_cursor.lnum += resel_VIsual_line_count * cap->count0 - 1; + check_cursor(); } VIsual_mode = resel_VIsual_mode; if (VIsual_mode == 'v') { diff --git a/src/nvim/ops.c b/src/nvim/ops.c index 1a12cb636a..b2554cbf0d 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -922,8 +922,8 @@ int do_record(int c) // The recorded text contents. p = get_recorded(); if (p != NULL) { - // Remove escaping for CSI and K_SPECIAL in multi-byte chars. - vim_unescape_csi(p); + // Remove escaping for K_SPECIAL in multi-byte chars. + vim_unescape_ks(p); (void)tv_dict_add_str(dict, S_LEN("regcontents"), (const char *)p); } @@ -933,7 +933,7 @@ int do_record(int c) buf[1] = NUL; (void)tv_dict_add_str(dict, S_LEN("regname"), buf); - // Get the recorded key hits. K_SPECIAL and CSI will be escaped, this + // Get the recorded key hits. K_SPECIAL will be escaped, this // needs to be removed again to put it in a register. exec_reg then // adds the escaping back later. apply_autocmds(EVENT_RECORDINGLEAVE, NULL, NULL, false, curbuf); @@ -1099,7 +1099,7 @@ int do_execreg(int regname, int colon, int addcr, int silent) return FAIL; } } - escaped = vim_strsave_escape_csi(reg->y_array[i]); + escaped = vim_strsave_escape_ks(reg->y_array[i]); retval = ins_typebuf(escaped, remap, 0, true, silent); xfree(escaped); if (retval == FAIL) { @@ -1141,7 +1141,7 @@ static void put_reedit_in_typebuf(int silent) /// Insert register contents "s" into the typeahead buffer, so that it will be /// executed again. /// -/// @param esc when true then it is to be taken literally: Escape CSI +/// @param esc when true then it is to be taken literally: Escape K_SPECIAL /// characters and no remapping. /// @param colon add ':' before the line static int put_in_typebuf(char_u *s, bool esc, bool colon, int silent) @@ -1156,7 +1156,7 @@ static int put_in_typebuf(char_u *s, bool esc, bool colon, int silent) char_u *p; if (esc) { - p = vim_strsave_escape_csi(s); + p = vim_strsave_escape_ks(s); } else { p = s; } @@ -2801,7 +2801,7 @@ static void yank_copy_line(yankreg_T *reg, struct block_def *bd, size_t y_idx, if (exclude_trailing_space) { int s = bd->textlen + bd->endspaces; - while (ascii_iswhite(*(bd->textstart + s - 1)) && s > 0) { + while (s > 0 && ascii_iswhite(*(bd->textstart + s - 1))) { s = s - utf_head_off(bd->textstart, bd->textstart + s - 1) - 1; pnew--; } diff --git a/src/nvim/os/input.c b/src/nvim/os/input.c index 3790eba212..54cfaee80a 100644 --- a/src/nvim/os/input.c +++ b/src/nvim/os/input.c @@ -234,9 +234,9 @@ size_t input_enqueue(String keys) while (rbuffer_space(input_buffer) >= 19 && ptr < end) { // A "<x>" form occupies at least 1 characters, and produces up // to 19 characters (1 + 5 * 3 for the char and 3 for a modifier). - // In the case of K_SPECIAL(0x80) or CSI(0x9B), 3 bytes are escaped and - // needed, but since the keys are UTF-8, so the first byte cannot be - // K_SPECIAL(0x80) or CSI(0x9B). + // In the case of K_SPECIAL(0x80), 3 bytes are escaped and needed, + // but since the keys are UTF-8, so the first byte cannot be + // K_SPECIAL(0x80). uint8_t buf[19] = { 0 }; unsigned int new_size = trans_special((const uint8_t **)&ptr, (size_t)(end - ptr), buf, true, @@ -263,12 +263,8 @@ size_t input_enqueue(String keys) continue; } - // copy the character, escaping CSI and K_SPECIAL - if ((uint8_t)*ptr == CSI) { - rbuffer_write(input_buffer, (char *)&(uint8_t){ K_SPECIAL }, 1); - rbuffer_write(input_buffer, (char *)&(uint8_t){ KS_EXTRA }, 1); - rbuffer_write(input_buffer, (char *)&(uint8_t){ KE_CSI }, 1); - } else if ((uint8_t)*ptr == K_SPECIAL) { + // copy the character, escaping K_SPECIAL + if ((uint8_t)(*ptr) == K_SPECIAL) { rbuffer_write(input_buffer, (char *)&(uint8_t){ K_SPECIAL }, 1); rbuffer_write(input_buffer, (char *)&(uint8_t){ KS_SPECIAL }, 1); rbuffer_write(input_buffer, (char *)&(uint8_t){ KE_FILLER }, 1); diff --git a/src/nvim/path.c b/src/nvim/path.c index 674d67e21a..39e276e0a5 100644 --- a/src/nvim/path.c +++ b/src/nvim/path.c @@ -1682,6 +1682,10 @@ char_u *find_file_name_in_path(char_u *ptr, size_t len, int options, long count, char_u *file_name; char_u *tofree = NULL; + if (len == 0) { + return NULL; + } + if ((options & FNAME_INCL) && *curbuf->b_p_inex != NUL) { tofree = (char_u *)eval_includeexpr((char *)ptr, len); if (tofree != NULL) { @@ -1743,14 +1747,32 @@ int path_is_url(const char *p) return 0; } -/// Check if "fname" starts with "name://". Return URL_SLASH if it does. +/// Check if "fname" starts with "name://" or "name:\\". /// /// @param fname is the filename to test -/// @return URL_BACKSLASH for "name:\\", zero otherwise. +/// @return URL_SLASH for "name://", URL_BACKSLASH for "name:\\", zero otherwise. int path_with_url(const char *fname) { const char *p; - for (p = fname; isalpha(*p); p++) {} + + // We accept alphabetic characters and a dash in scheme part. + // RFC 3986 allows for more, but it increases the risk of matching + // non-URL text. + + // first character must be alpha + if (!isalpha(*fname)) { + return 0; + } + + // check body: alpha or dash + for (p = fname; (isalpha(*p) || (*p == '-')); p++) {} + + // check last char is not a dash + if (p[-1] == '-') { + return 0; + } + + // "://" or ":\\" must follow return path_is_url(p); } diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c index 70a5c7aa08..a2d855244c 100644 --- a/src/nvim/terminal.c +++ b/src/nvim/terminal.c @@ -1299,7 +1299,7 @@ static bool send_mouse_event(Terminal *term, int c) } end: - ins_char_typebuf(c); + ins_char_typebuf(c, mod_mask); return true; } diff --git a/src/nvim/testdir/test_buffer.vim b/src/nvim/testdir/test_buffer.vim index 40111fdf06..a31cdbb49a 100644 --- a/src/nvim/testdir/test_buffer.vim +++ b/src/nvim/testdir/test_buffer.vim @@ -1,5 +1,7 @@ " Tests for Vim buffer +source check.vim + func Test_buffer_error() new foo1 new foo2 @@ -30,4 +32,33 @@ func Test_balt() call assert_equal('OtherBuffer', bufname()) endfunc +" Test for buffer match URL(scheme) check +" scheme is alpha and inner hyphen only. +func Test_buffer_scheme() + CheckMSWindows + + set noshellslash + %bwipe! + let bufnames = [ + \ #{id: 'b0', name: 'test://xyz/foo/b0' , match: 1}, + \ #{id: 'b1', name: 'test+abc://xyz/foo/b1', match: 0}, + \ #{id: 'b2', name: 'test_abc://xyz/foo/b2', match: 0}, + \ #{id: 'b3', name: 'test-abc://xyz/foo/b3', match: 1}, + \ #{id: 'b4', name: '-test://xyz/foo/b4' , match: 0}, + \ #{id: 'b5', name: 'test-://xyz/foo/b5' , match: 0}, + \] + for buf in bufnames + new `=buf.name` + if buf.match + call assert_equal(buf.name, getbufinfo(buf.id)[0].name) + else + " slashes will have become backslashes + call assert_notequal(buf.name, getbufinfo(buf.id)[0].name) + endif + bwipe + endfor + + set shellslash& +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_compiler.vim b/src/nvim/testdir/test_compiler.vim index aaa2301bca..c0c572ce65 100644 --- a/src/nvim/testdir/test_compiler.vim +++ b/src/nvim/testdir/test_compiler.vim @@ -19,6 +19,9 @@ func Test_compiler() call assert_equal('perl', b:current_compiler) call assert_fails('let g:current_compiler', 'E121:') + let verbose_efm = execute('verbose set efm') + call assert_match('Last set from .*[/\\]compiler[/\\]perl.vim ', verbose_efm) + call setline(1, ['#!/usr/bin/perl -w', 'use strict;', 'my $foo=1']) w! call feedkeys(":make\<CR>\<CR>", 'tx') diff --git a/src/nvim/testdir/test_conceal.vim b/src/nvim/testdir/test_conceal.vim index 1306dbe5cf..bffc2f49d3 100644 --- a/src/nvim/testdir/test_conceal.vim +++ b/src/nvim/testdir/test_conceal.vim @@ -4,10 +4,10 @@ source check.vim CheckFeature conceal source screendump.vim -" CheckScreendump func Test_conceal_two_windows() CheckScreendump + let code =<< trim [CODE] let lines = ["one one one one one", "two |hidden| here", "three |hidden| three"] call setline(1, lines) @@ -111,6 +111,7 @@ endfunc func Test_conceal_with_cursorline() CheckScreendump + " Opens a help window, where 'conceal' is set, switches to the other window " where 'cursorline' needs to be updated when the cursor moves. let code =<< trim [CODE] @@ -139,6 +140,7 @@ endfunc func Test_conceal_resize_term() CheckScreendump + let code =<< trim [CODE] call setline(1, '`one` `two` `three` `four` `five`, the backticks should be concealed') setl cocu=n cole=3 diff --git a/src/nvim/testdir/test_ex_mode.vim b/src/nvim/testdir/test_ex_mode.vim index 92e0559618..78663f7deb 100644 --- a/src/nvim/testdir/test_ex_mode.vim +++ b/src/nvim/testdir/test_ex_mode.vim @@ -98,4 +98,14 @@ func Test_ex_mode_count_overflow() call delete('Xexmodescript') endfunc +func Test_ex_mode_large_indent() + new + set ts=500 ai + call setline(1, "\t") + exe "normal gQi\<CR>." + set ts=8 noai + bwipe! +endfunc + + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_filetype.vim b/src/nvim/testdir/test_filetype.vim index 7db05e34d5..eb4824aa32 100644 --- a/src/nvim/testdir/test_filetype.vim +++ b/src/nvim/testdir/test_filetype.vim @@ -76,6 +76,7 @@ let s:filename_checks = { \ 'ave': ['file.ave'], \ 'awk': ['file.awk', 'file.gawk'], \ 'b': ['file.mch', 'file.ref', 'file.imp'], + \ 'basic': ['file.bas', 'file.bi', 'file.bm'], \ 'bzl': ['file.bazel', 'file.bzl', 'WORKSPACE'], \ 'bc': ['file.bc'], \ 'bdf': ['file.bdf'], @@ -186,43 +187,54 @@ let s:filename_checks = { \ 'fortran': ['file.f', 'file.for', 'file.fortran', 'file.fpp', 'file.ftn', 'file.f77', 'file.f90', 'file.f95', 'file.f03', 'file.f08'], \ 'fpcmake': ['file.fpc'], \ 'framescript': ['file.fsl'], - \ 'freebasic': ['file.fb', 'file.bi'], + \ 'freebasic': ['file.fb'], \ 'fsharp': ['file.fs', 'file.fsi', 'file.fsx'], \ 'fstab': ['fstab', 'mtab'], + \ 'fusion': ['file.fusion'], \ 'fvwm': ['/.fvwm/file', 'any/.fvwm/file'], \ 'gdb': ['.gdbinit', 'gdbinit'], + \ 'gdresource': ['file.tscn', 'file.tres'], + \ 'gdscript': ['file.gd'], \ 'gdmo': ['file.mo', 'file.gdmo'], \ 'gedcom': ['file.ged', 'lltxxxxx.txt', '/tmp/lltmp', '/tmp/lltmp-file', 'any/tmp/lltmp', 'any/tmp/lltmp-file'], \ 'gemtext': ['file.gmi', 'file.gemini'], \ 'gift': ['file.gift'], \ 'gitcommit': ['COMMIT_EDITMSG', 'MERGE_MSG', 'TAG_EDITMSG', 'NOTES_EDITMSG', 'EDIT_DESCRIPTION'], - \ 'gitconfig': ['file.git/config', '.gitconfig', '.gitmodules', 'file.git/modules//config', '/.config/git/config', '/etc/gitconfig', '/etc/gitconfig.d/file', '/.gitconfig.d/file', 'any/.config/git/config', 'any/.gitconfig.d/file', 'some.git/config', 'some.git/modules/any/config'], + \ 'gitconfig': ['file.git/config', 'file.git/config.worktree', 'file.git/worktrees/x/config.worktree', '.gitconfig', '.gitmodules', 'file.git/modules//config', '/.config/git/config', '/etc/gitconfig', '/usr/local/etc/gitconfig', '/etc/gitconfig.d/file', '/.gitconfig.d/file', 'any/.config/git/config', 'any/.gitconfig.d/file', 'some.git/config', 'some.git/modules/any/config'], \ 'gitolite': ['gitolite.conf', '/gitolite-admin/conf/file', 'any/gitolite-admin/conf/file'], \ 'gitrebase': ['git-rebase-todo'], \ 'gitsendemail': ['.gitsendemail.msg.xxxxxx'], \ 'gkrellmrc': ['gkrellmrc', 'gkrellmrc_x'], + \ 'glsl': ['file.glsl'], \ 'gnash': ['gnashrc', '.gnashrc', 'gnashpluginrc', '.gnashpluginrc'], - \ 'gnuplot': ['file.gpi'], + \ 'gnuplot': ['file.gpi', '.gnuplot'], \ 'go': ['file.go'], \ 'gomod': ['go.mod'], + \ 'gowork': ['go.work'], \ 'gp': ['file.gp', '.gprc'], \ 'gpg': ['/.gnupg/options', '/.gnupg/gpg.conf', '/usr/any/gnupg/options.skel', 'any/.gnupg/gpg.conf', 'any/.gnupg/options', 'any/usr/any/gnupg/options.skel'], \ 'grads': ['file.gs'], + \ 'graphql': ['file.graphql', 'file.graphqls', 'file.gql'], \ 'gretl': ['file.gretl'], \ 'groovy': ['file.gradle', 'file.groovy'], \ 'group': ['any/etc/group', 'any/etc/group-', 'any/etc/group.edit', 'any/etc/gshadow', 'any/etc/gshadow-', 'any/etc/gshadow.edit', 'any/var/backups/group.bak', 'any/var/backups/gshadow.bak', '/etc/group', '/etc/group-', '/etc/group.edit', '/etc/gshadow', '/etc/gshadow-', '/etc/gshadow.edit', '/var/backups/group.bak', '/var/backups/gshadow.bak'], \ 'grub': ['/boot/grub/menu.lst', '/boot/grub/grub.conf', '/etc/grub.conf', 'any/boot/grub/grub.conf', 'any/boot/grub/menu.lst', 'any/etc/grub.conf'], \ 'gsp': ['file.gsp'], \ 'gtkrc': ['.gtkrc', 'gtkrc', '.gtkrc-file', 'gtkrc-file'], + \ 'hack': ['file.hack', 'file.hackpartial'], \ 'haml': ['file.haml'], \ 'hamster': ['file.hsm'], + \ 'handlebars': ['file.hbs'], \ 'haskell': ['file.hs', 'file.hsc', 'file.hs-boot', 'file.hsig'], \ 'haste': ['file.ht'], \ 'hastepreproc': ['file.htpp'], \ 'hb': ['file.hb'], + \ 'hcl': ['file.hcl'], \ 'hercules': ['file.vc', 'file.ev', 'file.sum', 'file.errsum'], + \ 'heex': ['file.heex'], \ 'hex': ['file.hex', 'file.h32'], \ 'hgcommit': ['hg-editor-file.txt'], + \ 'hjson': ['file.hjson'], \ 'hog': ['file.hog', 'snort.conf', 'vision.conf'], \ 'hollywood': ['file.hws'], \ 'hostconf': ['/etc/host.conf', 'any/etc/host.conf'], @@ -264,6 +276,7 @@ let s:filename_checks = { \ 'jovial': ['file.jov', 'file.j73', 'file.jovial'], \ 'jproperties': ['file.properties', 'file.properties_xx', 'file.properties_xx_xx', 'some.properties_xx_xx_file'], \ 'json': ['file.json', 'file.jsonp', 'file.json-patch', 'file.webmanifest', 'Pipfile.lock', 'file.ipynb', '.babelrc', '.eslintrc', '.prettierrc', '.firebaserc', 'file.slnf'], + \ 'json5': ['file.json5'], \ 'jsonc': ['file.jsonc'], \ 'jsp': ['file.jsp'], \ 'julia': ['file.jl'], @@ -277,6 +290,7 @@ let s:filename_checks = { \ 'latte': ['file.latte', 'file.lte'], \ 'ld': ['file.ld'], \ 'ldif': ['file.ldif'], + \ 'ledger': ['file.ldg', 'file.ledger', 'file.journal'], \ 'less': ['file.less'], \ 'lex': ['file.lex', 'file.l', 'file.lxx', 'file.l++'], \ 'lftp': ['lftp.conf', '.lftprc', 'anylftp/rc', 'lftp/rc', 'some-lftp/rc'], @@ -350,6 +364,7 @@ let s:filename_checks = { \ 'netrc': ['.netrc'], \ 'nginx': ['file.nginx', 'nginxfile.conf', 'filenginx.conf', 'any/etc/nginx/file', 'any/usr/local/nginx/conf/file', 'any/nginx/file.conf'], \ 'ninja': ['file.ninja'], + \ 'nix': ['file.nix'], \ 'nqc': ['file.nqc'], \ 'nroff': ['file.tr', 'file.nr', 'file.roff', 'file.tmac', 'file.mom', 'tmac.file'], \ 'nsis': ['file.nsi', 'file.nsh'], @@ -392,6 +407,7 @@ let s:filename_checks = { \ 'ppd': ['file.ppd'], \ 'ppwiz': ['file.it', 'file.ih'], \ 'privoxy': ['file.action'], + \ 'prisma': ['file.prisma'], \ 'proc': ['file.pc'], \ 'procmail': ['.procmail', '.procmailrc'], \ 'prolog': ['file.pdb'], @@ -402,10 +418,12 @@ let s:filename_checks = { \ 'ps1xml': ['file.ps1xml'], \ 'psf': ['file.psf'], \ 'psl': ['file.psl'], + \ 'pug': ['file.pug'], \ 'puppet': ['file.pp'], \ 'pyret': ['file.arr'], \ 'pyrex': ['file.pyx', 'file.pxd'], \ 'python': ['file.py', 'file.pyw', '.pythonstartup', '.pythonrc', 'file.ptl', 'file.pyi', 'SConstruct'], + \ 'ql': ['file.ql', 'file.qll'], \ 'quake': ['anybaseq2/file.cfg', 'anyid1/file.cfg', 'quake3/file.cfg', 'baseq2/file.cfg', 'id1/file.cfg', 'quake1/file.cfg', 'some-baseq2/file.cfg', 'some-id1/file.cfg', 'some-quake1/file.cfg'], \ 'radiance': ['file.rad', 'file.mat'], \ 'raku': ['file.pm6', 'file.p6', 'file.t6', 'file.pod6', 'file.raku', 'file.rakumod', 'file.rakudoc', 'file.rakutest'], @@ -487,6 +505,7 @@ let s:filename_checks = { \ 'stata': ['file.ado', 'file.do', 'file.imata', 'file.mata'], \ 'stp': ['file.stp'], \ 'sudoers': ['any/etc/sudoers', 'sudoers.tmp', '/etc/sudoers', 'any/etc/sudoers.d/file'], + \ 'surface': ['file.sface'], \ 'svg': ['file.svg'], \ 'svn': ['svn-commitfile.tmp', 'svn-commit-file.tmp', 'svn-commit.tmp'], \ 'swift': ['file.swift'], @@ -500,8 +519,10 @@ let s:filename_checks = { \ 'taskdata': ['pending.data', 'completed.data', 'undo.data'], \ 'taskedit': ['file.task'], \ 'tcl': ['file.tcl', 'file.tm', 'file.tk', 'file.itcl', 'file.itk', 'file.jacl', '.tclshrc', 'tclsh.rc', '.wishrc'], + \ 'teal': ['file.tl'], \ 'teraterm': ['file.ttl'], \ 'terminfo': ['file.ti'], + \ 'terraform': ['file.tfvars'], \ 'tex': ['file.latex', 'file.sty', 'file.dtx', 'file.ltx', 'file.bbl'], \ 'texinfo': ['file.texinfo', 'file.texi', 'file.txi'], \ 'texmf': ['texmf.cnf'], @@ -509,6 +530,7 @@ let s:filename_checks = { \ 'tf': ['file.tf', '.tfrc', 'tfrc'], \ 'tidy': ['.tidyrc', 'tidyrc', 'tidy.conf'], \ 'tilde': ['file.t.html'], + \ 'tla': ['file.tla'], \ 'tli': ['file.tli'], \ 'tmux': ['tmuxfile.conf', '.tmuxfile.conf', '.tmux-file.conf', '.tmux.conf', 'tmux-file.conf', 'tmux.conf', 'tmux.conf.local'], \ 'toml': ['file.toml', 'Gopkg.lock', 'Pipfile', '/home/user/.cargo/config'], @@ -569,6 +591,7 @@ let s:filename_checks = { \ 'xslt': ['file.xsl', 'file.xslt'], \ 'yacc': ['file.yy', 'file.yxx', 'file.y++'], \ 'yaml': ['file.yaml', 'file.yml'], + \ 'yang': ['file.yang'], \ 'raml': ['file.raml'], \ 'z8a': ['file.z8a'], \ 'zig': ['file.zig'], @@ -1146,4 +1169,65 @@ func Test_foam_file() filetype off endfunc +func Test_bas_file() + filetype on + + call writefile(['looks like BASIC'], 'Xfile.bas') + split Xfile.bas + call assert_equal('basic', &filetype) + bwipe! + + " Test dist#ft#FTbas() + + let g:filetype_bas = 'freebasic' + split Xfile.bas + call assert_equal('freebasic', &filetype) + bwipe! + unlet g:filetype_bas + + " FreeBASIC + + call writefile(["/' FreeBASIC multiline comment '/"], 'Xfile.bas') + split Xfile.bas + call assert_equal('freebasic', &filetype) + bwipe! + + call writefile(['#define TESTING'], 'Xfile.bas') + split Xfile.bas + call assert_equal('freebasic', &filetype) + bwipe! + + call writefile(['option byval'], 'Xfile.bas') + split Xfile.bas + call assert_equal('freebasic', &filetype) + bwipe! + + call writefile(['extern "C"'], 'Xfile.bas') + split Xfile.bas + call assert_equal('freebasic', &filetype) + bwipe! + + " QB64 + + call writefile(['$LET TESTING = 1'], 'Xfile.bas') + split Xfile.bas + call assert_equal('qb64', &filetype) + bwipe! + + call writefile(['OPTION _EXPLICIT'], 'Xfile.bas') + split Xfile.bas + call assert_equal('qb64', &filetype) + bwipe! + + " Visual Basic + + call writefile(['Attribute VB_NAME = "Testing"'], 'Xfile.bas') + split Xfile.bas + call assert_equal('vb', &filetype) + bwipe! + + call delete('Xfile.bas') + filetype off +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_ins_complete.vim b/src/nvim/testdir/test_ins_complete.vim index ce75799551..6803271c03 100644 --- a/src/nvim/testdir/test_ins_complete.vim +++ b/src/nvim/testdir/test_ins_complete.vim @@ -445,6 +445,28 @@ func Test_issue_7021() set completeslash= endfunc +func Test_pum_stopped_by_timer() + CheckScreendump + + let lines =<< trim END + call setline(1, ['hello', 'hullo', 'heeee', '']) + func StartCompl() + call timer_start(100, { -> execute('stopinsert') }) + call feedkeys("Gah\<C-N>") + endfunc + END + + call writefile(lines, 'Xpumscript') + let buf = RunVimInTerminal('-S Xpumscript', #{rows: 12}) + call term_sendkeys(buf, ":call StartCompl()\<CR>") + call TermWait(buf, 200) + call term_sendkeys(buf, "k") + call VerifyScreenDump(buf, 'Test_pum_stopped_by_timer', {}) + + call StopVimInTerminal(buf) + call delete('Xpumscript') +endfunc + func Test_pum_with_folds_two_tabs() CheckScreendump diff --git a/src/nvim/testdir/test_usercommands.vim b/src/nvim/testdir/test_usercommands.vim index 29e578ac6d..481959d43d 100644 --- a/src/nvim/testdir/test_usercommands.vim +++ b/src/nvim/testdir/test_usercommands.vim @@ -269,10 +269,10 @@ endfunc func Test_CmdCompletion() call feedkeys(":com -\<C-A>\<C-B>\"\<CR>", 'tx') - call assert_equal('"com -addr bang bar buffer complete count nargs range register', @:) + call assert_equal('"com -addr bang bar buffer complete count keepscript nargs range register', @:) call feedkeys(":com -nargs=0 -\<C-A>\<C-B>\"\<CR>", 'tx') - call assert_equal('"com -nargs=0 -addr bang bar buffer complete count nargs range register', @:) + call assert_equal('"com -nargs=0 -addr bang bar buffer complete count keepscript nargs range register', @:) call feedkeys(":com -nargs=\<C-A>\<C-B>\"\<CR>", 'tx') call assert_equal('"com -nargs=* + 0 1 ?', @:) diff --git a/src/nvim/testdir/test_visual.vim b/src/nvim/testdir/test_visual.vim index d58ca92a2f..b087c88c35 100644 --- a/src/nvim/testdir/test_visual.vim +++ b/src/nvim/testdir/test_visual.vim @@ -1103,6 +1103,13 @@ func Test_visual_put_blockedit_zy_and_zp() bw! endfunc +func Test_visual_block_yank_zy() + new + " this was reading before the start of the line + exe "norm o\<C-T>\<Esc>\<C-V>zy" + bwipe! +endfunc + func Test_visual_block_with_virtualedit() CheckScreendump @@ -1120,7 +1127,61 @@ func Test_visual_block_with_virtualedit() " clean up call term_sendkeys(buf, "\<Esc>") call StopVimInTerminal(buf) - call delete('XTest_beval') + call delete('XTest_block') +endfunc + +func Test_visual_block_ctrl_w_f() + " Emtpy block selected in new buffer should not result in an error. + au! BufNew foo sil norm f + edit foo + + au! BufNew +endfunc + +func Test_visual_reselect_with_count() + " this was causing an illegal memory access + let lines =<< trim END + + + + : + r<sfile> + exe "%norm e3\<c-v>kr\t" + : + + : + END + call writefile(lines, 'XvisualReselect') + source XvisualReselect + + bwipe! + call delete('XvisualReselect') +endfunc + +" this was leaving the end of the Visual area beyond the end of a line +func Test_visual_ex_copy_line() + new + call setline(1, ["aaa", "bbbbbbbbbxbb"]) + /x + exe "normal ggvjfxO" + t0 + normal gNU + bwipe! +endfunc + +" This was leaving the end of the Visual area beyond the end of a line. +" Set 'undolevels' to start a new undo block. +func Test_visual_undo_deletes_last_line() + new + call setline(1, ["aaa", "ccc", "dyd"]) + set undolevels=100 + exe "normal obbbbbbbbbxbb\<Esc>" + set undolevels=100 + /y + exe "normal ggvjfxO" + undo + normal gNU + bwipe! endfunc diff --git a/src/nvim/undo.c b/src/nvim/undo.c index d18f35a43a..2d8df4cad8 100644 --- a/src/nvim/undo.c +++ b/src/nvim/undo.c @@ -2633,6 +2633,10 @@ static void u_undo_end(bool did_undo, bool absolute, bool quiet) } } + if (VIsual_active) { + check_pos(curbuf, &VIsual); + } + smsg_attr_keep(0, _("%" PRId64 " %s; %s #%" PRId64 " %s"), u_oldcount < 0 ? (int64_t)-u_oldcount : (int64_t)u_oldcount, diff --git a/test/functional/api/command_spec.lua b/test/functional/api/command_spec.lua index 6c2c136edc..d64d324a88 100644 --- a/test/functional/api/command_spec.lua +++ b/test/functional/api/command_spec.lua @@ -16,8 +16,8 @@ local feed = helpers.feed local funcs = helpers.funcs describe('nvim_get_commands', function() - local cmd_dict = { addr=NIL, bang=false, bar=false, complete=NIL, complete_arg=NIL, count=NIL, definition='echo "Hello World"', name='Hello', nargs='1', range=NIL, register=false, script_id=0, } - local cmd_dict2 = { addr=NIL, bang=false, bar=false, complete=NIL, complete_arg=NIL, count=NIL, definition='pwd', name='Pwd', nargs='?', range=NIL, register=false, script_id=0, } + local cmd_dict = { addr=NIL, bang=false, bar=false, complete=NIL, complete_arg=NIL, count=NIL, definition='echo "Hello World"', name='Hello', nargs='1', range=NIL, register=false, keepscript=false, script_id=0, } + local cmd_dict2 = { addr=NIL, bang=false, bar=false, complete=NIL, complete_arg=NIL, count=NIL, definition='pwd', name='Pwd', nargs='?', range=NIL, register=false, keepscript=false, script_id=0, } before_each(clear) it('gets empty list if no commands were defined', function() @@ -59,11 +59,11 @@ describe('nvim_get_commands', function() end) it('gets various command attributes', function() - local cmd0 = { addr='arguments', bang=false, bar=false, complete='dir', complete_arg=NIL, count='10', definition='pwd <args>', name='TestCmd', nargs='1', range='10', register=false, script_id=0, } - local cmd1 = { addr=NIL, bang=false, bar=false, complete='custom', complete_arg='ListUsers', count=NIL, definition='!finger <args>', name='Finger', nargs='+', range=NIL, register=false, script_id=1, } - local cmd2 = { addr=NIL, bang=true, bar=false, complete=NIL, complete_arg=NIL, count=NIL, definition='call \128\253R2_foo(<q-args>)', name='Cmd2', nargs='*', range=NIL, register=false, script_id=2, } - local cmd3 = { addr=NIL, bang=false, bar=true, complete=NIL, complete_arg=NIL, count=NIL, definition='call \128\253R3_ohyeah()', name='Cmd3', nargs='0', range=NIL, register=false, script_id=3, } - local cmd4 = { addr=NIL, bang=false, bar=false, complete=NIL, complete_arg=NIL, count=NIL, definition='call \128\253R4_just_great()', name='Cmd4', nargs='0', range=NIL, register=true, script_id=4, } + local cmd0 = { addr='arguments', bang=false, bar=false, complete='dir', complete_arg=NIL, count='10', definition='pwd <args>', name='TestCmd', nargs='1', range='10', register=false, keepscript=false, script_id=0, } + local cmd1 = { addr=NIL, bang=false, bar=false, complete='custom', complete_arg='ListUsers', count=NIL, definition='!finger <args>', name='Finger', nargs='+', range=NIL, register=false, keepscript=false, script_id=1, } + local cmd2 = { addr=NIL, bang=true, bar=false, complete=NIL, complete_arg=NIL, count=NIL, definition='call \128\253R2_foo(<q-args>)', name='Cmd2', nargs='*', range=NIL, register=false, keepscript=false, script_id=2, } + local cmd3 = { addr=NIL, bang=false, bar=true, complete=NIL, complete_arg=NIL, count=NIL, definition='call \128\253R3_ohyeah()', name='Cmd3', nargs='0', range=NIL, register=false, keepscript=false, script_id=3, } + local cmd4 = { addr=NIL, bang=false, bar=false, complete=NIL, complete_arg=NIL, count=NIL, definition='call \128\253R4_just_great()', name='Cmd4', nargs='0', range=NIL, register=true, keepscript=false, script_id=4, } source([[ command -complete=custom,ListUsers -nargs=+ Finger !finger <args> ]]) diff --git a/test/functional/api/extmark_spec.lua b/test/functional/api/extmark_spec.lua index c027cfb5eb..3f79515949 100644 --- a/test/functional/api/extmark_spec.lua +++ b/test/functional/api/extmark_spec.lua @@ -1448,6 +1448,49 @@ describe('API/extmarks', function() }) eq({ {1, 0, 0, { end_col = 0, end_row = 1 }} }, get_extmarks(ns, 0, -1, {details=true})) end) + + it('can get details', function() + set_extmark(ns, marks[1], 0, 0, { + end_col = 0, + end_row = 1, + priority = 0, + hl_eol = true, + hl_mode = "blend", + hl_group = "String", + virt_text = { { "text", "Statement" } }, + virt_text_pos = "right_align", + virt_text_hide = true, + virt_lines = { { { "lines", "Statement" } }}, + virt_lines_above = true, + virt_lines_leftcol = true, + }) + set_extmark(ns, marks[2], 0, 0, { + priority = 0, + virt_text = { { "text", "Statement" } }, + virt_text_win_col = 1, + }) + eq({0, 0, { + end_col = 0, + end_row = 1, + priority = 0, + hl_eol = true, + hl_mode = "blend", + hl_group = "String", + virt_text = { { "text", "Statement" } }, + virt_text_pos = "right_align", + virt_text_hide = true, + virt_lines = { { { "lines", "Statement" } }}, + virt_lines_above = true, + virt_lines_leftcol = true, + } }, get_extmark_by_id(ns, marks[1], { details = true })) + eq({0, 0, { + priority = 0, + virt_text = { { "text", "Statement" } }, + virt_text_hide = false, + virt_text_pos = "win_col", + virt_text_win_col = 1, + } }, get_extmark_by_id(ns, marks[2], { details = true })) + end) end) describe('Extmarks buffer api with many marks', function() diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index 22201e21a2..201ba45803 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -1367,18 +1367,18 @@ describe('API', function() end) describe('nvim_feedkeys', function() - it('CSI escaping', function() + it('K_SPECIAL escaping', function() local function on_setup() -- notice the special char(…) \xe2\80\xa6 nvim('feedkeys', ':let x1="…"\n', '', true) -- Both nvim_replace_termcodes and nvim_feedkeys escape \x80 local inp = helpers.nvim('replace_termcodes', ':let x2="…"<CR>', true, true, true) - nvim('feedkeys', inp, '', true) -- escape_csi=true + nvim('feedkeys', inp, '', true) -- escape_ks=true - -- nvim_feedkeys with CSI escaping disabled + -- nvim_feedkeys with K_SPECIAL escaping disabled inp = helpers.nvim('replace_termcodes', ':let x3="…"<CR>', true, true, true) - nvim('feedkeys', inp, '', false) -- escape_csi=false + nvim('feedkeys', inp, '', false) -- escape_ks=false helpers.stop() end diff --git a/test/functional/core/channels_spec.lua b/test/functional/core/channels_spec.lua index 93dec9fb35..c28300f0f4 100644 --- a/test/functional/core/channels_spec.lua +++ b/test/functional/core/channels_spec.lua @@ -100,6 +100,38 @@ describe('channels', function() eq({"notification", "exit", {3,0}}, next_msg()) end) + it('can use stdio channel and on_print callback', function() + source([[ + let g:job_opts = { + \ 'on_stdout': function('OnEvent'), + \ 'on_stderr': function('OnEvent'), + \ 'on_exit': function('OnEvent'), + \ } + ]]) + meths.set_var("nvim_prog", nvim_prog) + meths.set_var("code", [[ + function! OnStdin(id, data, event) dict + echo string([a:id, a:data, a:event]) + if a:data == [''] + quit + endif + endfunction + function! OnPrint(text) dict + call chansend(g:x, ['OnPrint:' .. a:text]) + endfunction + let g:x = stdioopen({'on_stdin': funcref('OnStdin'), 'on_print':'OnPrint'}) + call chansend(x, "hello") + ]]) + command("let g:id = jobstart([ g:nvim_prog, '-u', 'NONE', '-i', 'NONE', '--cmd', 'set noswapfile', '--headless', '--cmd', g:code], g:job_opts)") + local id = eval("g:id") + ok(id > 0) + + eq({ "notification", "stdout", {id, { "hello" } } }, next_msg()) + + command("call chansend(id, 'howdy')") + eq({"notification", "stdout", {id, {"OnPrint:[1, ['howdy'], 'stdin']"}}}, next_msg()) + end) + local function expect_twoline(id, stream, line1, line2, nobr) local msg = next_msg() local joined = nobr and {line1..line2} or {line1, line2} diff --git a/test/functional/editor/meta_key_spec.lua b/test/functional/editor/meta_key_spec.lua index 2280f5bb24..f811b8ae8d 100644 --- a/test/functional/editor/meta_key_spec.lua +++ b/test/functional/editor/meta_key_spec.lua @@ -27,6 +27,14 @@ describe('meta-keys #8226 #13042', function() command('nnoremap <A-j> Aalt-j<Esc>') feed('<A-j><M-l>') expect('llo<ESC>;<ESC>;alt-jmeta-l') + -- Unmapped ALT-chord with characters containing K_SPECIAL bytes + command('nnoremap … A…<Esc>') + feed('<A-…><M-…>') + expect('llo<ESC>;<ESC>;alt-jmeta-l<ESC>…<ESC>…') + command("execute 'nnoremap' nr2char(0x40000000) 'AMAX<Esc>'") + command("call nvim_input('<A-'.nr2char(0x40000000).'>')") + command("call nvim_input('<M-'.nr2char(0x40000000).'>')") + expect('llo<ESC>;<ESC>;alt-jmeta-l<ESC>…<ESC>…<ESC>MAX<ESC>MAX') end) it('ALT/META, visual-mode', function() @@ -36,13 +44,20 @@ describe('meta-keys #8226 #13042', function() expect('peach') -- Unmapped ALT-chord resolves isolated (non-ALT) ESC mapping. #13086 #15869 command('vnoremap <ESC> A<lt>ESC>') - feed('viw<A-;><ESC>viw<M-;><ESC>') + feed('viw<A-;><Esc>viw<M-;><Esc>') expect('peach<ESC>;<ESC>;') -- Mapped ALT-chord behaves as mapped. command('vnoremap <M-l> Ameta-l<Esc>') command('vnoremap <A-j> Aalt-j<Esc>') feed('viw<A-j>viw<M-l>') expect('peach<ESC>;<ESC>;alt-jmeta-l') + -- Unmapped ALT-chord with characters containing K_SPECIAL bytes + feed('viw<A-…><Esc>viw<M-…><Esc>') + expect('peach<ESC>;<ESC>;alt-jmeta-l<ESC>…<ESC>…') + command("execute 'inoremap' nr2char(0x40000000) 'MAX'") + command("call nvim_input('viw<A-'.nr2char(0x40000000).'><Esc>')") + command("call nvim_input('viw<M-'.nr2char(0x40000000).'><Esc>')") + expect('peach<ESC>;<ESC>;alt-jmeta-l<ESC>…<ESC>…<ESC>MAX<ESC>MAX') end) it('ALT/META insert-mode', function() diff --git a/test/functional/terminal/mouse_spec.lua b/test/functional/terminal/mouse_spec.lua index 780a0b9b5a..6e2c851df7 100644 --- a/test/functional/terminal/mouse_spec.lua +++ b/test/functional/terminal/mouse_spec.lua @@ -1,7 +1,7 @@ local helpers = require('test.functional.helpers')(after_each) local thelpers = require('test.functional.terminal.helpers') local clear, eq, eval = helpers.clear, helpers.eq, helpers.eval -local feed, nvim = helpers.feed, helpers.nvim +local feed, nvim, command = helpers.feed, helpers.nvim, helpers.command local feed_data = thelpers.feed_data describe(':terminal mouse', function() @@ -10,9 +10,9 @@ describe(':terminal mouse', function() before_each(function() clear() nvim('set_option', 'statusline', '==========') - nvim('command', 'highlight StatusLine cterm=NONE') - nvim('command', 'highlight StatusLineNC cterm=NONE') - nvim('command', 'highlight VertSplit cterm=NONE') + command('highlight StatusLine cterm=NONE') + command('highlight StatusLineNC cterm=NONE') + command('highlight VertSplit cterm=NONE') screen = thelpers.screen_setup() local lines = {} for i = 1, 30 do @@ -38,6 +38,26 @@ describe(':terminal mouse', function() eq('nt', eval('mode(1)')) end) + it('will exit focus and trigger Normal mode mapping on mouse click', function() + command('let g:got_leftmouse = 0') + command('nnoremap <LeftMouse> <Cmd>let g:got_leftmouse = 1<CR>') + eq('t', eval('mode(1)')) + eq(0, eval('g:got_leftmouse')) + feed('<LeftMouse>') + eq('nt', eval('mode(1)')) + eq(1, eval('g:got_leftmouse')) + end) + + it('will exit focus and trigger Normal mode mapping on mouse click with modifier', function() + command('let g:got_ctrl_leftmouse = 0') + command('nnoremap <C-LeftMouse> <Cmd>let g:got_ctrl_leftmouse = 1<CR>') + eq('t', eval('mode(1)')) + eq(0, eval('g:got_ctrl_leftmouse')) + feed('<C-LeftMouse>') + eq('nt', eval('mode(1)')) + eq(1, eval('g:got_ctrl_leftmouse')) + end) + it('will exit focus on <C-\\> + mouse-scroll', function() eq('t', eval('mode(1)')) feed('<C-\\>') @@ -180,7 +200,7 @@ describe(':terminal mouse', function() it('will forward mouse clicks to the program with the correct even if set nu', function() if helpers.pending_win32(pending) then return end - nvim('command', 'set number') + command('set number') -- When the display area such as a number is clicked, it returns to the -- normal mode. feed('<LeftMouse><3,0>') diff --git a/test/functional/ui/bufhl_spec.lua b/test/functional/ui/bufhl_spec.lua index 16ed3b9486..7716414e87 100644 --- a/test/functional/ui/bufhl_spec.lua +++ b/test/functional/ui/bufhl_spec.lua @@ -755,12 +755,24 @@ describe('Buffer highlighting', function() -- TODO: only a virtual text from the same ns curretly overrides -- an existing virtual text. We might add a prioritation system. set_virtual_text(id1, 0, s1, {}) - eq({{1, 0, 0, { priority = 0, virt_text = s1}}}, get_extmarks(id1, {0,0}, {0, -1}, {details=true})) + eq({{1, 0, 0, { + priority = 0, + virt_text = s1, + -- other details + virt_text_pos = 'eol', + virt_text_hide = false, + }}}, get_extmarks(id1, {0,0}, {0, -1}, {details=true})) -- TODO: is this really valid? shouldn't the max be line_count()-1? local lastline = line_count() set_virtual_text(id1, line_count(), s2, {}) - eq({{3, lastline, 0, { priority = 0, virt_text = s2}}}, get_extmarks(id1, {lastline,0}, {lastline, -1}, {details=true})) + eq({{3, lastline, 0, { + priority = 0, + virt_text = s2, + -- other details + virt_text_pos = 'eol', + virt_text_hide = false, + }}}, get_extmarks(id1, {lastline,0}, {lastline, -1}, {details=true})) eq({}, get_extmarks(id1, {lastline+9000,0}, {lastline+9000, -1}, {})) end) diff --git a/test/functional/ui/input_spec.lua b/test/functional/ui/input_spec.lua index ea8968a653..11718a6e18 100644 --- a/test/functional/ui/input_spec.lua +++ b/test/functional/ui/input_spec.lua @@ -114,11 +114,30 @@ describe('mappings', function() end) end) -describe('input utf sequences that contain CSI/K_SPECIAL', function() +describe('input utf sequences that contain K_SPECIAL (0x80)', function() it('ok', function() feed('i…<esc>') expect('…') end) + + it('can be mapped', function() + command('inoremap … E280A6') + feed('i…<esc>') + expect('E280A6') + end) +end) + +describe('input utf sequences that contain CSI (0x9B)', function() + it('ok', function() + feed('iě<esc>') + expect('ě') + end) + + it('can be mapped', function() + command('inoremap ě C49B') + feed('iě<esc>') + expect('C49B') + end) end) describe('input non-printable chars', function() diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua index d7f43ca18c..84bf28e83e 100644 --- a/test/functional/ui/popupmenu_spec.lua +++ b/test/functional/ui/popupmenu_spec.lua @@ -2271,6 +2271,47 @@ describe('builtin popupmenu', function() assert_alive() end) + it('is closed by :stopinsert from timer #12976', function() + screen:try_resize(32,14) + command([[call setline(1, ['hello', 'hullo', 'heeee', ''])]]) + feed('Gah<C-N>') + screen:expect([[ + hello | + hullo | + heeee | + hello^ | + {s:hello }{1: }| + {n:hullo }{1: }| + {n:heeee }{1: }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {2:-- }{5:match 1 of 3} | + ]]) + command([[call timer_start(100, { -> execute('stopinsert') })]]) + helpers.sleep(200) + feed('k') -- cursor should move up in Normal mode + screen:expect([[ + hello | + hullo | + heee^e | + hello | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]) + end) + it('truncates double-width character correctly when there is no scrollbar', function() screen:try_resize(32,8) command('set completeopt+=menuone,noselect') diff --git a/test/unit/path_spec.lua b/test/unit/path_spec.lua index 15ce59747e..fb476397e6 100644 --- a/test/unit/path_spec.lua +++ b/test/unit/path_spec.lua @@ -626,4 +626,20 @@ describe('path.c', function() eq(false, path_with_extension('/some/path/file', 'lua')) end) end) + + describe('path_with_url', function() + itp('scheme is alpha and inner hyphen only', function() + local function path_with_url(fname) + return cimp.path_with_url(to_cstr(fname)) + end + eq(1, path_with_url([[test://xyz/foo/b0]])) + eq(2, path_with_url([[test:\\xyz\foo\b0]])) + eq(0, path_with_url([[test+abc://xyz/foo/b1]])) + eq(0, path_with_url([[test_abc://xyz/foo/b2]])) + eq(1, path_with_url([[test-abc://xyz/foo/b3]])) + eq(2, path_with_url([[test-abc:\\xyz\foo\b3]])) + eq(0, path_with_url([[-test://xyz/foo/b4]])) + eq(0, path_with_url([[test-://xyz/foo/b5]])) + end) + end) end) diff --git a/third-party/CMakeLists.txt b/third-party/CMakeLists.txt index 1a8d7701a8..cdca7c7b9c 100644 --- a/third-party/CMakeLists.txt +++ b/third-party/CMakeLists.txt @@ -203,8 +203,8 @@ set(LIBICONV_SHA256 ccf536620a45458d26ba83887a983b96827001e92a13847b45e4925cc891 set(TREESITTER_C_URL https://github.com/tree-sitter/tree-sitter-c/archive/v0.20.1.tar.gz) set(TREESITTER_C_SHA256 ffcc2ef0eded59ad1acec9aec4f9b0c7dd209fc1a85d85f8b0e81298e3dddcc2) -set(TREESITTER_URL https://github.com/tree-sitter/tree-sitter/archive/2346570901ef01517dad3e4a944a36d7b7237e4f.tar.gz) -set(TREESITTER_SHA256 d4df622491f3689f71d77ab4dcd26c85ad44a40bbd1ebe831e34658ba48cdc9f) +set(TREESITTER_URL https://github.com/tree-sitter/tree-sitter/archive/v0.20.3.tar.gz) +set(TREESITTER_SHA256 ab52fe93e0c658cff656b9d10d67cdd29084247052964eba13ed6f0e9fa3bd36) if(USE_BUNDLED_UNIBILIUM) include(BuildUnibilium) |