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) | 
