Skip to content

Instantly share code, notes, and snippets.

@ZyX-I
Last active August 22, 2021 07:06
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save ZyX-I/4af839e000e7eada347d to your computer and use it in GitHub Desktop.
Save ZyX-I/4af839e000e7eada347d to your computer and use it in GitHub Desktop.
Incompatibilities list from neovim/neovim#387

Here I will list all incompatibilities between old and new VimL implementations. Some may be fixed, so it is also a place for discussion. Please discuss incompatibilities with separate issues in separate issues.

Expressions parser incompatibilities

  • Dot subscripts are not always read correctly (#240).
  • E15 errors are not not just “E15: Invalid expression”: there are (invalid expressions)
    • “E15: expected variable name” (\x80\xFD\x52)
    • “E15: expected expr7 (value)” (+)
    • “E15: missing closing curly brace” (a{1)
  • E116 error was renamed: “E116: expected closing parenthesis”.
  • No nested expr errors: function(a{}) will produce one “E15: expected expr7 (value)”, not E15, E15, E116 and E15 errors at once (only E15 can be caught though).
  • Positions of error may differ.
  • Environment variable name is determined on the parsing stage. But what part of a string is environment variable name depends on &isident option which may be different on the stage where expression is actually run. (I really would rather prefer to remove dependency completely: say work like if value is non-standard @,48-57,_,128-255 effectively including all UTF-8 characters (just in case), but not things like /. Standard ones are @,48-57,_,128-167,224-235 (MS-DOS, Win32, OS/2) and @,48-57,_,192-255 (otherwise) which means that e.g. $ENV«» is parsed as ($ENV<c2>)<ab>: pretty useless.)

Command parser incompatibilities

  • append works slightly different:

          append
          abc
          .
    

    is always correct with my parser, but it may be not correct with old vim parser: depends on context. I failed to comprehend why, but inside functions append with indented first line and same indented dot does not work, while it works correctly inside files.

  • Missing block endings (:endif, :endfor, etc) in :autocmd do generate errors.

  • Incomplete blocks (:if, etc) in :autocmd definition are not supported.

  • If you mix tabs and spaces in indentation append uses the value of &tabstop option to deduce whether dot is on its place (which is very strange because code suggests it uses 8-wide tabs: I must have missed something (like fgetline transforming tabs to spaces)). My parser uses only 8-wide tabs.

  • endfunction in vim is a marker that is read by ex_function() which is the reason why function A()|endfunction does not work. In my parser it is a separate command that ends a :function block, so there is no requirement for :endfunction to be the first command in the line.

  • :call accepts any function calls, not necessary calls in the form funcname(args) (funcname may actually be something like dic{"tionary"}['name'], but not (function("tr"))). I.e. it will work as long as top node is function call node.

  • “E129: Function name required” was renamed to “E129: :call accepts only function calls”.

  • “E117: Unknown function” may be replaced with “E117: Attempt to call a non-function” when using :call.

  • :for/:let messages are different: E475 was split into

    • “E475: Expected variable name or a list of variable names” (for 1 in []) (was “E690: Missing "in" after :for” for for)
    • “E475: Expected non-empty list of variable names” (for [] in [])
    • “E475: Expected variable name” (for [1] in [])
  • :let E474 is now “E474: To list multiple variables use "let var|let var2", not ":let [var, var2]"”.

  • :let 1 will show “E475: Expected variable name or a list of variable names”, not “E121: Undefined variable”.

  • “E125: Illegal argument” was split into

    • “E125: Argument expected, got nothing” (:function Abc(,))
    • “E125: Function argument cannot start with a digit” (:function Abc(1))
    • “E125: Names "firstline" and "lastline" are reserved” (:function Abc(firstline))
  • “E475” for :function now looks either like “E475: Expected end of arguments list” or “E475: Expected end of arguments list or comma”.

  • “E475” for :behave now looks like “E475: :behave command currently only supports mswin and xterm”.

  • For debug commands “E475” was split into

    • “E475: Profile commands only accept func' and file' as their first argument” (for :profile foo),
    • “E475: Debug commands only accept func', file' and here'” (for :break… foo`),
    • “E475: Expecting function name or pattern” (for :break… func, :break… func 123 or :profile… func without further arguments) and
    • “E475: Expecting file name or pattern” (for :break… file, :break… file 123 or :profile… file without further arguments).
  • “E474” from :cbuffer and friends is now “E474: Expected buffer number”.

  • :fu Abc()|echo1|endf is parsed as a correct function definition. Used to produce missing endfunction errors.

  • Certain function definitions cannot be parsed. See #425.

  • ilist /inslashes/afterslashes will complain about trailing characters, but not run anything (in Vim it will first search then complain). Same for similar commands.

  • “E216” is always “No such event” (in Vim this may have been “No such group or event”). Any string that does not start with a star and contains no whitespaces is treated like an autocmd group name. Note: augroup accepts any sequence of characters as an autocmd group, including BufWritePre and this is a group name with spaces and \| bar. I cannot do anything with groups with whitespaces, but anything else is accepted.

  • Leading autocmd group name which is identical to some autocmd event name (e.g. BufWritePre), * or a list of event names (e.g. BufWritePre,BufReadPre) is not parsed as an autocmd group name when parsing :au definition (I really have no idea why this should be allowed, but even if I thought having group name like BufWritePre is a good idea I cannot do anything with this at the parsing stage).

  • “E474” from :delmarks was transformed into “E474: :delmarks must be called either without bang or without arguments” (:delmarks! some_argument).

  • “E475” from :delmarks was split into

    • “E475: Trying to construct range out of marks from different sets” (:delmarks 0-A).
    • “E475: Upper range bound is less then lower range bound” (:delmarks z-a).
    • “E475: Unknown mark” (:delmarks @).
  • “E471” from :delmarks is now “E471: You must specify register(s)”.

  • “E474” from :digraphs was transformed into “E474: Expected second digraph character, but got nothing” (:digraphs a)

  • :digraphs accepts two characters in the digraph definition (was: two bytes, which I consider a bug).

  • “E475” from :later/:earlier was split into

    • “E475: Expected 's', 'm', 'h', 'd', 'f' or nothing after number” (:later 10x).
    • “E475: Trailing characters” (:later 10mx).
    • “E475: Expected numeric argument” (:later x).
  • “E475” from :filetype is now “E475: Invalid syntax: expected `filetype[ [plugin|indent]... {on|off|detect}]'”.

  • ++opt E474 was split into

    • “E474: Expected ++[no]bin or ++[no]binary” (e ++binxxx)
    • “E474: Unknown ++opt” (e ++unknown)
    • “E474: Option requires argument: use ++opt=arg” (e ++enc)
    • “E474: Invalid ++bad argument: use "keep", "drop" or a single-byte character” (e ++bad=xxx)
    • “E474: Invalid ++ff argument” (e ++ff=ttt)
  • “E488” from :history was split into

    • “E488: Expected history type name or nothing” (:history garbage)
    • “E488: Expected valid history lines range” (:history ,)
  • “E488” from :clist and friends is now “E488: Expected valid integer range”.

  • “E471” from :mark/:k is now “E471: Expected mark name”.

  • :mark no longer allows setting <, >, [, ] and " marks (according to the doc it never did).

  • “E475” from :redir was split into

    • “E475: Expected `END', `>[>] {file}', `@{register}[>[>]]' or `=> {variable}': redir!!!” (:redir without arguments or with invalid argument)
    • “E475: Expected END'” (:redir e`)
    • “E475: Expected register name; one of A-Z, a-z, ", * and +” (:redir @?)
    • “E475: Expected `>' and variable name”
  • “E475” from :match is now “E475: Expected regular expression” (:match HlGroup without last argument).

  • “E474” from :set was split into

    • “E474: Expected `>'” (:set <C-a).
    • “E474: Cannot set boolean options with `=' or `:'” (:set number=0).
    • “E474: Expected `=', `:', `&' or `<'” (:set nocb-).
    • “E474: Cannot invert or unset non-boolean option” (:set noclipboard).
    • “E474: Expected key definition” (:set wcm=<C-a).
  • “E475” from :sleep is now “E475: Expected `m' or nothing”.

  • Any error in expression after \= in :substitute will result in :substitute command not executed at all, not in :substitute command spamming error on each occurence of pattern it is to replace.

  • Parser that has no way to know whether :s is going to occur inside another :s and always parses expressions after \= dictates allowing nested \= expressions at least for :s.

  • “E474” from :sort is now “E474: Can only specify one kind of numeric sort”.

  • “E475” from :sort is now “E475: Expected sort flag or non-ASCII regular expression delimiter”.

  • “E475” from :syntime is now “E475: Expected one action of `on', `off', `clear' or `report'”.

  • “E474” from :wincmd was split into

    • “E474: Expected extended window action (see help tags starting with CTRL-W_g)” (:wincmd g).
    • “E474: Trailing characters” (:wincmd ogarbage).
  • “E791” from :loadkeymap was split into

    • “E791: Empty LHS” (loading keymap line that starts with a blank).
    • “E791: Empty RHS” (loading keymap line that has only one sequence of non-whitespace characters).
  • LHS+RHS length in :loadkeymap is no longer limited to 200 characters.

  • “E474” from :menutranslate was split into

    • “E474: Expected translated string” (:menutranslate Foo).
    • “E474: Expected string that is to be translated” (:menutranslate).
    • “E474: Expected no submenus” (:menutranslate Foo.Bar).
  • “E475” from :highlight is now “E475: Missing closing quote”.

  • “E239” from :sign was split into

    • “E239: Non-printable character in sign text” (:exe "sign define Foo text=\e").
    • “E239: Failed to process complete sign text” (not sure whether this can happen at all).
    • “E239: Sign text is too wide” (:sign define Foo text=1).
    • “E239: Sign text is too narrow” (:sign define Foo text=123).
  • “E475” from :sign is now “E475: Unknown sign property” (:sign define Foo xxx=>>).

  • “E474” from :sign was split into

    • “E474: Cannot use `*' when identifier was already given” (:sign unplace 1 *).
    • “E474: Unknown property” (:sign place 1 foo).
    • “E474: Must provide either buffer= or file= as the last argument” (:sign place 1 line=10 name=Foo).
    • “E474: Cannot use zero as sign id” (:sign place 0).
    • “E474: Cannot use line= and name= without a sign id” (:sign place line=10 buffer=1).
    • “E474: Cannot use line= and name= with :sign jump” (:sign jump 10 line=10 buffer=1).
    • “E474: Cannot use line= and name= with :sign unplace” (:sign unplace 10 line=10 buffer=1).
    • “E474: Missing sign name” (:sign place 10 line=10 buffer=1).
  • “E488” from :sign may now be “E488: buffer= argument must be the last one”.

  • “E158” from :sign is now only (it used to be emitted for any error regarding buffers failed to be found) “E158: Buffer number can only be positive” (:sign place 1 line=10 name=Foo buffer=-10).

  • “E885” from :sign is now only “E885: Can only use positive line numbers” (:sign place 1 line=-1).

  • Calling :sign with non-positive line number fails always (used to fail only if placed sign identifier is new identifier).

  • “E390” from :syntax case is now “E390: Expected match or ignore”.

  • “E390” from :syntax conceal is now “E390: Expected on or off”.

  • :syn cluster Foo add=A,B,C remove=C add=C or similar will probably not do what you want: such things are parsed into syn cluster Foo add=A,B,C,C remove=C (separate arguments are always parsed into one list and thus you will most likely end up with C in Foo cluster).

  • :syn cluster subarguments order is not preserved, executors are supposed to process them in order contains, add, remove.

  • “E475” from :syn cluster is now “E475: Expecting group name followed by an argument”.

  • “E402” from :syn match and others that accept patterns may be “E402: Expected offset anchor designator (`s' or `e')” (syn match Foo /e/ms=x) or “E402: Garbage after pattern” like it was previously.

  • “E399” from :syn region may either be “E399: Expected group name” (syn region Foo matchgroup=) or “E399: Expected syntax pattern” (syn region Foo start=).

  • “E404” from :syn sync was split into

    • “E404: Expected `=number'” (syntax sync lines=x/syntax sync lines).
    • “E404: Pattern end not found” (syntax sync linecont /foo).
    • “E404: Unknown argument” (syntax sync xxx).
  • “E475” from :syntax keyword is now one of

    • “E475: Expected group name” (syntax keyword).
    • “E475: Expected keywords” (syntax keyword Foo).
  • “E475” from :syntax match is now one of

    • “E475: Expected group name followed by an argument” (syntax match Foo and syntax match).
    • “E475: Trailing characters” (syntax match Foo /bar/ /bar/).
  • Invalid range in glob pattern prevents pattern from being used, not emits an error and proceeds with treating this range literally.

  • “E16: Invalid range” is “E16: Invalid range: end is greater then start” in glob patterns.

  • Treatment of the “corner cases” like [a-[:alnum:]] differs.

  • It is currently not possible to fall back to “treat the file name literally” variant if pattern matching failed in many cases because parser does not save this information (this will be a few lines fix to save this information, but I do not think this is a good idea: if user meant a pattern he should get a pattern, if user meant no pattern then there is backslash at his service).

Translator incompatibilities

  • Parser errors out on the parsing stage in many cases, without leaving neovim a chance to evaluate any code. But vim errors out on the execution stage (as it does not have any other stages), evaluating whatever was placed before the error. E.g. in the following code:

      let list = [system('echo abc > def'),
    

    my parser is just going to complain about missing ], Vim is going to create file def and then complain about missing ].

  • In E119/E118 messages (not enough/too many arguments for function) in user functions function name are used exactly as they were defined. E.g. for the following function:

      let d = {}
      function d.Abc(a, b, c)
      endfunction
      call Abc(1)
    

    It will show

      E119: Not enough arguments for function: d.Abc
    

    , not

      E119: Not enough arguments for function: 42
    

    . I am planning to use this variant everywhere I need a function name: numbers are not descriptive at all.

  • Functions defined inside a dictionary are no longer dictionary functions (see below about relations between regular functions and self). Reasoning: I have lots of non-dictionary dictionary functions just because I have a reason to define them inside a dictionary in place of using regular s: functions. I do not like having to always care about {} as a third argument to call() in this case.

Lua implementation incompatibilities

  • E15 errors are not not just “E15: Invalid expression”: there are (invalid expressions)

    • “E15: Can only call a Funcref” (let d={'a':1}|let i=d.a(1))
  • string[{}], string[[]] and string[function('tr')] will complain about using Dictionary/List/Funcref as a Number, not as a String. Same for list[...]. Not the case for dictionary[...].

  • string[0.0] will not raise E806: Using Float as a String. Same for list[0.0]. Not the case for dictionary[...].

  • [] == {} and {} == [] in Vim both complain about lists that can only be compared with lists. After translation first complains about comparing lists, second about comparing dictionaries.

  • Trying to define function inside a dictionary if corresponding key already exists may throw “E718: Funcref required” if existing value is not a function and “E717: Dictionary entry already exists” if existing value is a function. I think that first error is a bug and always raise “E717”.

  • Using :delfunction acts like :unlet, but also deletes global function if it exists. The difference is that if you put function reference into a dictionary this reference will be removed from the dictionary when you run delfunction. But it will not be removed at least from a) scope variables and b) lists. Code:

    execute "function S()\nendfunction"
    execute "function L()\nendfunction"
    let Funcref = function('S')
    let l = [function('L')]
    delfunction Funcref
    echo Funcref
    " Will complain about undefined variable in my branch and show S in Vim
    delfunction l
    echo l
    " Will output [function('L')] in Vim, [] in my translator.
  • Trying to delete a slice with :delfunction will emit “E475: Expecting function reference, not List” in place of “E475: Invalid argument”.

  • Trying to add two dictionaries ({} + {}) will result in “E728: Using Dictionary as a Number” and not “E731: Using Dictionary as a String”. Same for {} + [].

  • Trying to represent recursive containers will result in lots of brackets and a error. I do not have explicit recursion limit (lua(jit) may have one though) and do not use iterative version of string(), but both string() and :echo check for recursive containers resulting in the former emitting error earlier:

    let l = []
    call add(l, l)
    echo string(l)
    " Vim: echoes “E724: Variable nested too deep for displaying” and
    " [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[{E724}]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]
    " (One hundred of opening brackets, exactly. Same for closing, of course.)
    
    " My translator: echoes “E724: Recursive data type detected” and
    " [{E724}]
  • Trying to change the value of the variable never raises E706. Reasoning: I never saw this error making me do anything useful, but constantly saw it as a source of bugs when processing heterogenous lists.

  • “E710” error message changed: “List value has too many items” (in Vim: “List value has more items than target”). Reason: consistency with “E711: List value has not enough items”.

  • “E684: List index out of range” is sometimes seen as “E684: First index is greater than the second”. Specifically this happens when trying to (un)lock or unlet [1:0].

  • When deleting variable with :unlet locks are ignored, but not if :unlet g:.var syntax is used (i.e. locks are ignored only when using :unlet g:var). Current implementation ignores locks always when deleting from scope dictionaries, no matter how they are accessed.

  • string() always uses %e format for floating-point values.

Other

  • Dictionary and non-dictionary user functions have the only difference of requiring to have self dictionary for calling them. E.g. calling dictionary function without a dictionary will fail, but one may
    • Call non-dictionary function with a dictionary and observe self variable set to this dictionary. Since E706 is out it only makes difference for the case when one tries to access self without setting it which should be rare (usually this name is not used anywhere, but in dictionary functions).
    • Set self in a dictionary function to a different value (in Vim it raises E46).
  • Due to the nature of the idea of having a parser it currently needs to parse the whole block before executing something. I.e. if in Vim you type :while 1<CR>echo 1 you will immediately see 1, but it will not repeat until endwhile. I can add some hacks to preserve this behavior, but do not see any sense in doing this right now and see not very much sense in doing this later.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment