Dev_vimpatch

Nvim :help pages, generated from source using the tree-sitter-vimdoc parser.


Merging patches from Vim
Nvim was forked from Vim 7.4.160; it is kept up-to-date with relevant Vim patches in order to avoid duplicate work. Run vim-patch.sh to see the status of Vim patches:
./scripts/vim-patch.sh -l
Everyone is welcome to create a dev-vimpatch-pr for relevant Vim patches, but some types of patches are dev-vimpatch-na. See dev-vimpatch-quickstart to get started immediately.
Pull the Nvim source:
git clone https://github.com/neovim/neovim.git
Run ./scripts/vim-patch.sh -l to see the list of missing Vim patches.
Choose a patch from the list (usually the oldest one), e.g. 8.0.0123.
Run ./scripts/vim-patch.sh -p 8.0.0123
Follow the instructions given by the script.

NOTES

It's strongly recommended to work on the oldest missing patch, because later patches might depend on the changes.
Use git log --grep or git log -G to search the Nvim/Vim source history (even deleted code). E.g. to find reset_option_was_set:


git log -p -G reset_option_was_set
Pass git log options like --grep and -G to ./scripts/vim-patch.sh -L to filter unmerged Vim patches E.g. to find +quickfix patches:


./scripts/vim-patch.sh -L --grep quickfix -- src

PULL REQUESTS dev-vimpatch-pr

Note: vim-patch.sh automates these steps for you. Use it!
Install gh (https://cli.github.com/) if you want to use vim-patch.sh to create PRs automatically
The pull request title should include vim-patch:8.x.xxxx (no whitespace)
A token indicating the Vim patch number, formatted as follows: vim-patch:8.0.0123 (no whitespace)
The original Vim commit message, including author
Reviewers: hint for reviewing runtime/ patches https://github.com/neovim/neovim/pull/1744#issuecomment-68202876

NA (NOT APPLICABLE) PATCHES dev-vimpatch-na

Most Vim patches are not applicable to Nvim. If you find NA patches, visit an the latest "version.c: update" pull request https://github.com/neovim/neovim/pulls?q=is%3Apr+author%3Aapp%2Fgithub-actions+version.c+is%3Aopen and mention the NA patches in a comment (please edit/update one comment, rather than adding a new comment for each patch).
Or if there is no open version.c: update pull request, include NA patches in a commit message in this format:
vim-patch:<version-or-commit>

vim-patch:<version-or-commit>

...
where <version-or-commit> is a valid Vim version (like 8.0.0123) or commit-id (SHA). Each patch is on a separate line.

HOW TO DECIDE IF A VIM-PATCH IS WANTED

Legacy Vim is becoming much less relevant to Nvim: we expect to decline the majority of their patches. Thus this is an "allow-list" instead of a "deny-list". Generally, only modules explicitly noted in the "OWNED BY VIM" list below, are in-scope; everything else should be marked "N/A".

OWNED BY VIM

quickfix
regex
runtime files
Everything else is owned by Nvim. Most of Vim's "bug fixes" for e.g. buffer/window behavior, or the events/autocmds subysytem, or "getchar" (input engine), just aren't relevant to Nvim anymore, because we've significantly enhanced and redesigned those subsystems to make them simpler.

UNWANTED VIM-PATCHES

"channel"
"job"
"tabpanel"
"terminal"
Vim9script features, and anything related to :scriptversion. (Nvim supports Vimscript version 1 only.)
Fixes for build warnings.
GUI-related changes.
Most new Vimscript functions or Ex commands (with rare exceptions).
The list of Vim patches in src/nvim/version.c is automatically updated https://github.com/neovim/neovim/pull/7780 based on the presence of vim-patch:xxx tokens in the Nvim git log.
Don't update src/nvim/version.c yourself.
scripts/vim-patch.sh -p intentionally omits version.c to avoid merge conflicts and save time when porting a patch.
The automation script (scripts/vimpatch.lua) only recognizes tokens like vim-patch:8.0.1206, not vim-patch:<hash>.

CODE DIFFERENCES dev-vimpatch-diff

The following functions have been removed or deprecated in favor of newer alternatives. See memory.c https://github.com/neovim/neovim/blob/master/src/nvim/memory.c for more information.
-----------------------------------------------------------------------

Deprecated or removed                                 Replacement

-----------------------------------------------------------------------

vim_free                                                 xfree

VIM_CLEAR(&foo)                                    XFREE_CLEAR(foo)

malloc alloc lalloc lalloc_id ALLOC_ONE                 xmalloc

calloc lalloc_clear                                     xcalloc

realloc vim_realloc                                    xrealloc

mch_memmove                                             memmove

vim_memset copy_chars copy_spaces                       memset

vim_strbyte                                             strchr

vim_strncpy strncpy                               xstrlcpy/xmemcpyz

vim_strcat strncat                                     xstrlcat

VIM_ISWHITE                                          ascii_iswhite

IS_WHITE_OR_NUL                                  ascii_iswhite_or_nul

IS_WHITE_NL_OR_NUL                              ascii_iswhite_nl_or_nul

vim_isalpha                                           mb_isalpha

vim_isNormalIDc                                      ascii_isident

vim_islower vim_isupper                          mb_islower mb_isupper

vim_tolower vim_toupper                          mb_tolower mb_toupper

mb_ptr2len                                           utfc_ptr2len

mb_ptr2len_len                                     utfc_ptr2len_len

mb_char2len                                          utf_char2len

mb_char2bytes                                       utf_char2bytes

mb_ptr2cells                                         utf_ptr2cells

mb_ptr2cells_len                                   utf_ptr2cells_len

mb_char2cells                                       utf_char2cells

mb_off2cells                                         utf_off2cells

mb_ptr2char                                          utf_ptr2char

mb_head_off                                          utf_head_off

mb_tail_off                                          utf_cp_bounds

mb_strnicmp2                                         utf_strnicmp

MB_STRNICMP2                                         utf_strnicmp

mb_lefthalve                                        grid_lefthalve

mb_fix_col                                           grid_fix_col

utf_off2cells                                       grid_off2cells

ml_get_curline                                    get_cursor_line_ptr

ml_get_cursor                                     get_cursor_pos_ptr

ml_get_curline_len                                get_cursor_line_len

ml_get_cursor_len                                 get_cursor_pos_len

screen_char                                             ui_line

screen_line                                        grid_put_linebuf

screen_* (most functions)                               grid_*

update_prepare, update_finish #9484                  removed; use update_screen only

ARRAY_LENGTH                                          ARRAY_SIZE

vim_strsave_escape_csi                           vim_strsave_escape_ks

vim_unescape_csi                                    vim_unescape_ks

gettail                                                path_tail

mch_isFullName                                     path_is_absolute

script_do_profile                                    profile_init



-----------------------------------------------------------------------
Make sure to note the difference between utf_ and utfc_ when replacing mb_ functions. Also indirect call syntax (*mb_ptr2len)(...) should be replaced with an ordinary function call utfc_ptr2len(...).
-----------------------------------------------------------------------

Data type    Format (Vim source)     Portable format (Nvim source)

------------ ----------------------- ----------------------------------

long long    "%lld"                  "%" PRId64

size_t       "%ld"                   "%zu"

linenr_T     "%ld"                   "%" PRIdLINENR

-----------------------------------------------------------------------
Vim's ga_init2 was renamed to ga_init and the original ga_init is gone.
"Old style" Vim tests (src/testdir/*.in) should be converted to Lua tests (see #1286 https://github.com/neovim/neovim/issues/1286 and #1328 https://github.com/neovim/neovim/pull/1328). See Checklist for migrating legacy tests https://github.com/neovim/neovim/blob/master/test/README.md#checklist-for-migrating-legacy-tests.
However, please do not convert "new style" Vim tests (src/testdir/*.vim) to Lua. The "new style" Vim tests are faster than the old ones, and converting them takes time and effort better spent elsewhere. Just copy them to test/old/testdir/*.vim.
Conditions that check enc_utf8 or has_mbyte are obsolete (only the "true" case is applicable).
enc_utf8 and has_mbyte macros were removed in https://github.com/neovim/neovim/pull/13293
Check for CSI in typeahead buffer is only necessary in Vim with FEAT_GUI. CSI does not have a special meaning in typeahead buffer in Nvim. (also see https://github.com/neovim/neovim/pull/16936)

LIST MANAGEMENT dev-vimpatch-list-impl

Management of lists (types list_T and listitem_T from vim) was changed in https://github.com/neovim/neovim/pull/7708/. There is a lint against the "old" usage, but here are the most important changes.
Declarations for the table
list_T list: a list
listitem_T li: an item of list
int val a value for lv_copyID
--------------------------------------------------------------------------------------

Old                             New                                  Comment

------------------------------- ------------------------------------------------------

list->lv_first                  tv_list_first(list)

list->lv_last                   tv_list_last(list)

li->li_next                     TV_LIST_ITEM_NEXT(list, li)          To be avoided if possible, must use list which li belongs to.

li->li_prev                     TV_LIST_ITEM_PREV(list, li)          To be avoided if possible, must use list which li belongs to.

                                Suggestion by @ZyX-l:                Use TV_LIST_ITER or indexing instead of the previous two calls.

list->lv_len                    tv_list_len(list)

list->lv_lock                   tv_list_locked(list)

&li->li_tv                      TV_LIST_ITEM_TV(li)

list->lv_refcount++             tv_list_ref(list)

val = list->lv_copyID           val = tv_list_copyid(list)

list->lv_copyID = val           tv_list_set_copyid(list, val)



for (li = list->lv_first;       TV_LIST_ITER_CONST(list, li,         Use TV_LIST_ITER(...) if you need to

li != NULL && another_cond;     { if (another_cond) {break;} code})  modify list items (note: assigning copyID is also modification and this happens

li = li->li_next) code                                               always when recursively traversing a list).



--------------------------------------------------------------------------------------
For more details and some more advanced usage, see typval.h and typval.c.

DOCUMENTATION DIFFERENCES dev-vimpatch-doc

The following should be removed from all imported documentation, and not be used in new documentation:
{Only when compiled with ...}: the vast majority of features have been made non-optional (see https://github.com/neovim/neovim/wiki/Introduction)

FILETYPE DETECTION dev-vimpatch-filetype

Nvim's filetype detection behavior matches Vim, but is implemented as part of vim.filetype (see $VIMRUNTIME/lua/vim/filetype.lua). The logic is encoded in three tables, listed in order of precedence (the first match is returned):
filename for literal full path or basename lookup;
pattern for matching filenames or paths against lua-patterns, optimized for fast lookup;
extension for literal extension lookup.
Logic that requires checking file contents or buffer variables is implemented in $VIMRUNTIME/lua/vim/filetype/detect.lua.
When porting filetype patches from Vim, keep the following in mind:
Prefer explicit filenames or extensions over patterns, especially for case insensitive matches (see https://github.com/neovim/neovim/pull/29800):
"*[mM]akefile" regex -> "makefile", "Makefile" filenames

"*.js\c"       regex -> "js", "jS", "Js", "jS" extensions
Pattern matching has several differences:
It is done using explicit Lua patterns without implicit anchoring instead of Vim regexes:
"*/debian/changelog" -> "/debian/changelog$"

"*/bind/db.*"        -> "/bind/db%."
Filetype patterns are grouped by their parent pattern to improve matching performance: If the parent pattern does not match, skip testing all child patterns. Note that unlike leaf patterns, parent patterns do not have special matching behaviour if they contain a /.
When adding a new filetype with pattern matching, consider the following:
If there is already a group with appropriate parent pattern, use it.
If there can be a fast and specific enough pattern to group at least 3 filetype patterns, add it as a separate grouped entry.
New parent patterns should be
fast: rule of thumb is that it should be a short explicit string (i.e. no quantifiers or character sets);
specific: rules of thumb, in order:
full directory name (e.g., "/etc/", "/log/");
part of a rare enough directory name (e.g., "/conf", "git/");
string rarely used in real full paths (e.g., "nginx").
Example:
Filetype pattern: ".*/etc/a2ps/.*%.cfg"
Good parents: "/etc/" or "%.cfg$"
Bad parents: "%." (fast but not specific) or "/a2ps/.*%." (specific but slow)
When modifying an existing regular pattern, make sure that it still fits its group.
Main
Commands index
Quick reference