Problem: completion: various flaws in fuzzy completion
Solution: fix the issues (Girish Palya)
- Remove the brittle `qsort()` on `compl_match_array`.
- Add a stable, non-recursive `mergesort` for the internal doubly
linked list of matches.
- The sort now happens directly on the internal representation (`compl_T`),
preserving sync with external structures and making sorting stable.
- Update fuzzy match logic to enforce `max_matches` limits after
sorting.
- Remove `trim_compl_match_array()`, which is no longer necessary.
- Fixe test failures by correctly setting `selected` index and
maintaining match consistency.
- Introduce `mergesort_list()` in `misc2.c`, which operates generically
over doubly linked lists.
- Remove `pum_score` and `pum_idx` variables
fixes: vim/vim#17387closes: vim/vim#174308cd42a58b4
Co-authored-by: Girish Palya <girishji@gmail.com>
Problem:
1. The `Fixedgq()` function is broken (see vim/vim#17412)
2. The `'formatexpr'` for Typescript is not documented, which causes
confusion to users when they try to set `'formatprg'`, since
`'formatexpr'` always takes precedence over `'formatprg'`. See also
https://github.com/HerringtonDarkholme/yats.vim/issues/209
3. Typescript already has a very good and popular formatter called
`prettier`, that can be easily integrated to Vim via `'formatprg'`
(see vim/vim#16989). I don't think there are any good reasons to reinvent a
half-baked version in Vim.
Solution: Remove the Fixedgq() 'formatexpr' function.
fixes: vim/vim#17412closes: vim/vim#17452eb59129d2c
Problem: Unnecessary :if in session where both branches have the same
effect (after 9.1.1431).
Solution: Remove the superfluous :if (zeertzjq).
closes: vim/vim#174488f751d56f4
Problem: Hit-Enter Prompt when loading session files
Solution: use set+= for 'shortmess' to keep the existing flags
(Miguel Barro)
closes: vim/vim#174450ca5966196
Co-authored-by: Miguel Barro <miguel.barro@live.com>
Problem: Listing submenus with :menu doesn't work.
Solution: Don't go to the parent of the return value of find_menu(), and
handle empty path at the caller.
Related #8194, which actually only fixed the problem for menu_get(), not
for :menu Ex command.
- update the netrw window to current version (and trim it slightly to 80
chars)
- remove a trailing double quote
dfed077e06
Co-authored-by: Christian Brabandt <cb@256bit.org>
Co-authored-by: Antonio Giovanni Colombo <azc100@gmail.com>
Problem: When opening a new tabpage, extui windows are initialized with
their default config. Window visiblity/dimensions on other
tabpages may get out of sync with their buffer content.
Solution: Copy the config of the window to the new tabpage.
No longer keep track of the various windows on each tabpage.
Close windows on inactive tabpages instead (moving them could
be more efficient but is currently not supported in the API).
Problem: Two separate window messages are used to get
the original console icon and set a new
one on windows, although the `WM_SETICON`
message returns the original icon itself.
Solution: Replace the two `WM_GETICON` messages with
two `WM_SETICON` messages, save the return
values and remove the call to `os_icon_set`.
Also, replace `os_icon_set` with `os_icon_reset`
as its only usage is now resetting the
icon to the original one.
Problem:
`vim.diagnostic.set()` doesn't actually accept a list of
`vim.Diagnostic` as internally `vim.diagnostic.set()` normalizes the
diagnostics and this normalization is assumed throughout the module.
Solution:
- Add a new type `vim.Diagnostic.Set` which is the input to `vim.diagnostic.set()`
- `col` is now an optional field and defaults to `0` to be consistent
with `vim.diagnostic.match()`.
- Change `table.insert(t, x)` to `table[#table + 1] = x` for improved
type checking.
Fixes#34013
Problem:
when diagnostic is set right after EOL, underline handler looks
inconsistent compared to other handlers, visually underline is shown
starting from the next line. On top of that it's also inconsistent with
open_float and jump.
Solution:
clamp starting column position in underline handler to be right before
EOL to make it visible and consistent with other handlers, open_float
and jump.
Problem: "win" is cleared in float config after 96330843, even with
unchanged "relative".
Solution: Don't clear "win". Avoid erroring for deleted "win" by setting
the parent win to curwin directly when "win" is zero or not
present in config.
Problem: CTRL-X CTRL-R only completes individual words from registers,
making it difficult to insert complete register content.
Solution: Add consecutive CTRL-X CTRL-R support - first press completes
words, second press completes full register lines, similar to
CTRL-X CTRL-L and CTRL-X CTRL-P behavior (glepnir).
closes: vim/vim#17395d5fdfa5c9c
Co-authored-by: glepnir <glephunter@gmail.com>
Problem: PMenu selection broken with multi-line selection and limits
(Maxim Kim)
Solution: update completion match index when limiting the completion
sources (Girish Palya)
fixes: vim/vim#17394closes: vim/vim#174016c40df09e0
Co-authored-by: Girish Palya <girishji@gmail.com>
Problem: scheduling of complete function can be improved
Solution: call user completion functions earlier when just determining
the insertion column (Girish Palya)
This change improves the scheduling behavior of async user-defined
completion functions (such as `F{func}`, `F`, or `'o'` values in the
`'complete'` option), particularly benefiting LSP clients.
Currently, these user functions are invoked twice:
1. First with `findstart = 1` to determine the completion start
position.
2. Then with `findstart = 0` to retrieve the actual matches.
Previously, both calls were executed back-to-back. With this change, the
first call (`findstart = 1`) is performed earlier—before any matches are
gathered from other sources.
This adjustment gives event-driven completion sources (e.g., LSP
clients) more time to send their requests while Vim concurrently
collects matches from other sources like the current buffer.
Not sure about the real-world performance gains, but this approach
should, in theory, improve responsiveness and reduce latency for
asynchronous completions.
To test, try using yegappan LSP client:
```vim
set cpt+=o^10
autocmd VimEnter * g:LspOptionsSet({ autoComplete: false, omniComplete: true })
```
If you prefer to use 'native' auto-completion (without plugins), try the
following configuration:
```vim
set cot=menuone,popup,noselect,nearest
autocmd TextChangedI * InsComplete()
def InsComplete()
if getcharstr(1) == '' && getline('.')->strpart(0, col('.') - 1) =~ '\k$'
SkipTextChangedI()
feedkeys("\<c-n>", "n")
endif
enddef
inoremap <silent> <c-e> <c-r>=<SID>SkipTextChangedI()<cr><c-e>
inoremap <silent> <c-y> <c-r>=<SID>SkipTextChangedI()<cr><c-y>
def SkipTextChangedI(): string
set eventignore+=TextChangedI
timer_start(1, (_) => {
set eventignore-=TextChangedI
})
return ''
enddef
inoremap <silent><expr> <tab> pumvisible() ? "\<c-n>" : "\<tab>"
inoremap <silent><expr> <s-tab> pumvisible() ? "\<c-p>" : "\<s-tab>"
```
closes: vim/vim#1739698c29dbfd1
Co-authored-by: Girish Palya <girishji@gmail.com>
Problem: using f-flag in 'complete' conflicts with Neovims filename
completion (glepnir, after v9.1.1301).
Solution: use upper-case "F" flag for completion functions
(Girish Palya).
fixes: vim/vim#17347closes: vim/vim#1737814f6da5ba8
Co-authored-by: Girish Palya <girishji@gmail.com>
Problem: compile warning about uninitialized value
(Tony Mechelynck, after v9.1.1311)
Solution: initialize variable on declaration
b53d4fb63e
Co-authored-by: Christian Brabandt <cb@256bit.org>
Problem: completion: not possible to limit number of matches
Solution: allow to limit the matches for 'complete' sources by using the
"{flag}^{limit}" notation (Girish Palya)
This change extends the 'complete' option to support limiting the
number of matches returned from individual completion sources.
**Rationale:** In large files, certain sources (such as the current
buffer) can generate an overwhelming number of matches, which may cause
more relevant results from other sources (e.g., LSP or tags) to be
pushed out of view. By specifying per-source match limits, the
completion menu remains balanced and diverse, improving visibility and
relevance of suggestions.
A caret (`^`) followed by a number can be appended to a source flag to
specify the maximum number of matches for that source. For example:
```
:set complete=.^9,w,u,t^5
```
In this configuration:
- The current buffer (`.`) will return up to 9 matches.
- The tag completion (`t`) will return up to 5 matches.
- Other sources (`w`, `u`) are not limited.
This feature is fully backward-compatible and does not affect behavior
when the `^count` suffix is not used.
The caret (`^`) was chosen as the delimiter because it is least likely
to appear in file names.
closes: vim/vim#170870ac1eb3555
Cherry-pick test_options.vim change from patch 9.1.1325.
Co-authored-by: Girish Palya <girishji@gmail.com>
Problem: Coverity warns about using uninitialized value
(Coverity, Tony Mechelynck, after v9.1.1301)
Solution: initialize callback pointer to NULL
d2079cff48
Co-authored-by: Christian Brabandt <cb@256bit.org>
Problem: completion: cannot configure completion functions with
'complete'
Solution: add support for setting completion functions using the f and o
flag for 'complete' (Girish Palya)
This change adds two new values to the `'complete'` (`'cpt'`) option:
- `f` – invokes the function specified by the `'completefunc'` option
- `f{func}` – invokes a specific function `{func}` (can be a string or `Funcref`)
These new flags extend keyword completion behavior (e.g., via `<C-N>` /
`<C-P>`) by allowing function-based sources to participate in standard keyword
completion.
**Key behaviors:**
- Multiple `f{func}` values can be specified, and all will be called in order.
- Functions should follow the interface defined in `:help complete-functions`.
- When using `f{func}`, escaping is required for spaces (with `\`) and commas
(with `\\`) in `Funcref` names.
- If a function sets `'refresh'` to `'always'`, it will be re-invoked on every
change to the input text. Otherwise, Vim will attempt to reuse and filter
existing matches as the input changes, which matches the default behavior of
other completion sources.
- Matches are inserted at the keyword boundary for consistency with other completion methods.
- If finding matches is time-consuming, `complete_check()` can be used to
maintain responsiveness.
- Completion matches are gathered in the sequence defined by the `'cpt'`
option, preserving source priority.
This feature increases flexibility of standard completion mechanism and may
reduce the need for external completion plugins for many users.
**Examples:**
Complete matches from [LSP](https://github.com/yegappan/lsp) client. Notice the use of `refresh: always` and `function()`.
```vim
set cpt+=ffunction("g:LspCompletor"\\,\ [5]). # maxitems = 5
def! g:LspCompletor(maxitems: number, findstart: number, base: string): any
if findstart == 1
return g:LspOmniFunc(findstart, base)
endif
return {words: g:LspOmniFunc(findstart, base)->slice(0, maxitems), refresh: 'always'}
enddef
autocmd VimEnter * g:LspOptionsSet({ autoComplete: false, omniComplete: true })
```
Complete matches from `:iabbrev`.
```vim
set cpt+=fAbbrevCompletor
def! g:AbbrevCompletor(findstart: number, base: string): any
if findstart > 0
var prefix = getline('.')->strpart(0, col('.') - 1)->matchstr('\S\+$')
if prefix->empty()
return -2
endif
return col('.') - prefix->len() - 1
endif
var lines = execute('ia', 'silent!')
if lines =~? gettext('No abbreviation found')
return v:none # Suppresses warning message
endif
var items = []
for line in lines->split("\n")
var m = line->matchlist('\v^i\s+\zs(\S+)\s+(.*)$')
if m->len() > 2 && m[1]->stridx(base) == 0
items->add({ word: m[1], info: m[2], dup: 1 })
endif
endfor
return items->empty() ? v:none :
items->sort((v1, v2) => v1.word < v2.word ? -1 : v1.word ==# v2.word ? 0 : 1)
enddef
```
**Auto-completion:**
Vim's standard completion frequently checks for user input while searching for
new matches. It is responsive irrespective of file size. This makes it
well-suited for smooth auto-completion. You can try with above examples:
```vim
set cot=menuone,popup,noselect inf
autocmd TextChangedI * InsComplete()
def InsComplete()
if getcharstr(1) == '' && getline('.')->strpart(0, col('.') - 1) =~ '\k$'
SkipTextChangedIEvent()
feedkeys("\<c-n>", "n")
endif
enddef
inoremap <silent> <c-e> <c-r>=<SID>SkipTextChangedIEvent()<cr><c-e>
def SkipTextChangedIEvent(): string
# Suppress next event caused by <c-e> (or <c-n> when no matches found)
set eventignore+=TextChangedI
timer_start(1, (_) => {
set eventignore-=TextChangedI
})
return ''
enddef
```
closes: vim/vim#17065cbe53191d0
Temporarily remove bufname completion with #if 0 to make merging easier.
Co-authored-by: Girish Palya <girishji@gmail.com>
Co-authored-by: Christian Brabandt <cb@256bit.org>
Co-authored-by: glepnir <glephunter@gmail.com>
Problem: preview-window does not scroll correctly
Solution: init firstline = 0 for a preview window
(Girish Palya)
The 'info' window, which appears during insert-mode completion to display
additional information, was not scrolling properly when using commands like:
win_execute(popup_findinfo(), "normal! \<PageDown>")
This issue made it impossible to navigate through info window contents using
keyboard-based scrolling.
The fix correctly updates the w_firstline value of the popup window, ensuring
proper scrolling behavior. Mouse scrolling was already working as expected and
remains unaffected.
closes: vim/vim#1670312b1eb58ab
Co-authored-by: Girish Palya <girishji@gmail.com>
Problem: Buffer setup after moving the message buffer to the "more"
window after ff95d7ff is incomplete.
Solution: Adjust and invoke tab_check_wins() to do the setup instead.
Problem: Closing the "more" window for an entered cmdwin in ff95d7ff9
still requires special casing to properly handle "more" visibility.
Solution: Reposition the "more" window instead; anchoring it to the
cmdwin.
Problem: Unable to change the "relative" of a flag after its target
"win" no longer exists.
Solution: Unset target window if it is not present in config and
reconfigured "relative" no longer expects a target window.
Problem:
Developing/troubleshooting plugins has friction because "restarting"
Nvim requires quitting and manually starting again. #32484
Solution:
- Implement a `:restart` command which emits `restart` UI event.
- Handle the `restart` UI event in the builtin TUI client: stop the
`nvim --embed` server, start a new one, and attach to it.
Complement the documented support for the recognition of all
public types of the "java.lang" package (":help java.vim").
(The original syntax item generator may have, inadvertently,
contributed via suppressing "NullPointerException"s to not
having annotation and interface types qualify in general.)
Also, re-link usage instructions for the alternative syntax
item generator to a rolling "master"'s version.
closes: vim/vim#17419b577ad50d0
Co-authored-by: Aliaksei Budavei <0x000c70@gmail.com>