Problem: Generating prototype files does not work on all platforms
Solution: Rework prototypes generation using python instead of cproto,
enable it in CI to test it for each PR (Hirohito Higashi).
closes: #18045
Signed-off-by: Hirohito Higashi <h.east.727@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: Option insecure flags not copied when splitting window.
Solution: Move window-local insecure flags to winopt_T and copy them
properly (zeertzjq).
closes: #18434
Signed-off-by: zeertzjq <zeertzjq@outlook.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: completion: 'autocomplete' cannot be enabled per buffer
(Tomasz N)
Solution: Make 'autocomplete' global or local to buffer (Girish Palya)
fixes: #18320closes: #18333
Signed-off-by: Girish Palya <girishji@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: fuzzy-matching can be improved
Solution: Implement a better fuzzy matching algorithm
(Girish Palya)
Replace fuzzy matching algorithm with improved fzy-based implementation
The
[current](https://www.forrestthewoods.com/blog/reverse_engineering_sublime_texts_fuzzy_match/)
fuzzy matching algorithm has several accuracy issues:
* It struggles with CamelCase
* It fails to prioritize matches at the beginning of strings, often
ranking middle matches higher.
After evaluating alternatives (see my comments
[here](https://github.com/vim/vim/issues/17531#issuecomment-3112046897)
and
[here](https://github.com/vim/vim/issues/17531#issuecomment-3121593900)),
I chose to adopt the [fzy](https://github.com/jhawthorn/fzy) algorithm,
which:
* Resolves the aforementioned issues.
* Performs better.
Implementation details
This version is based on the original fzy
[algorithm](https://github.com/jhawthorn/fzy/blob/master/src/match.c),
with one key enhancement: **multibyte character support**.
* The original implementation supports only ASCII.
* This patch replaces ascii lookup tables with function calls, making it
compatible with multibyte character sets.
* Core logic (`match_row()` and `match_positions()`) remains faithful to
the original, but now operates on codepoints rather than single-byte
characters.
Performance
Tested against a dataset of **90,000 Linux kernel filenames**. Results
(in milliseconds) show a **\~2x performance improvement** over the
current fuzzy matching algorithm.
```
Search String Current Algo FZY Algo
-------------------------------------------------
init 131.759 66.916
main 83.688 40.861
sig 98.348 39.699
index 109.222 30.738
ab 72.222 44.357
cd 83.036 54.739
a 58.94 62.242
b 43.612 43.442
c 64.39 67.442
k 40.585 36.371
z 34.708 22.781
w 38.033 30.109
cpa 82.596 38.116
arz 84.251 23.964
zzzz 35.823 22.75
dimag 110.686 29.646
xa 43.188 29.199
nha 73.953 31.001
nedax 94.775 29.568
dbue 79.846 25.902
fp 46.826 31.641
tr 90.951 55.883
kw 38.875 23.194
rp 101.575 55.775
kkkkkkkkkkkkkkkkkkkkkkkkkkkkk 48.519 30.921
```
```vim
vim9script
var haystack = readfile('/Users/gp/linux.files')
var needles = ['init', 'main', 'sig', 'index', 'ab', 'cd', 'a', 'b',
'c', 'k',
'z', 'w', 'cpa', 'arz', 'zzzz', 'dimag', 'xa', 'nha', 'nedax',
'dbue',
'fp', 'tr', 'kw', 'rp', 'kkkkkkkkkkkkkkkkkkkkkkkkkkkkk']
for needle in needles
var start = reltime()
var tmp = matchfuzzy(haystack, needle)
echom $'{needle}' (start->reltime()->reltimefloat() * 1000)
endfor
```
Additional changes
* Removed the "camelcase" option from both matchfuzzy() and
matchfuzzypos(), as it's now obsolete with the improved algorithm.
related: neovim/neovim#34101
fixes#17531closes: #17900
Signed-off-by: Girish Palya <girishji@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: completion: cannot use autoloaded funcs in 'complete' F{func}
(Maxim Kim)
Solution: Make it work (Girish Palya)
fixes: #17869closes: #17885
Signed-off-by: Girish Palya <girishji@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: Patch v8.1.0425 was wrong
Solution: Revert that patch (Hirohito Higashi)
This is because the root cause was fixed in 8.1.0786 and a regression
occurred elsewhere.
related: #3455
related: #3830fixes: #11558closes: #17899
Co-authored-by: zeertzjq <zeertzjq@outlook.com>
Signed-off-by: Hirohito Higashi <h.east.727@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: :bnext doesn't go to unlisted help buffers when cycling
through help buffers (after 9.1.0557).
Solution: Don't check if a help buffer is listed (zeertzjq).
From <https://github.com/vim/vim/issues/4478#issuecomment-498831057>:
> I think we should fix that, since once you get to a non-help buffer
> all unlisted buffers are skipped, thus you won't encounter another
> help buffer.
This implies that cycling through help buffers should work even if help
buffers are unlisted. Otherwise this part of :bnext isn't really useful,
as :h makes help buffers unlisted by default.
related: #4478
related: #15198closes: #17913
Signed-off-by: zeertzjq <zeertzjq@outlook.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: not possible to anchor specific lines in difff mode
Solution: Add support for the anchoring lines in diff mode using the
'diffanchor' option (Yee Cheng Chin).
Adds support for anchoring specific lines to each other while viewing a
diff. While lines are anchored, they are guaranteed to be aligned to
each other in a diff view, allowing the user to control and inform the
diff algorithm what the desired alignment is. Internally, this is done
by splitting up the buffer at each anchor and run the diff algorithm on
each split section separately, and then merge the results back for a
logically consistent diff result.
To do this, add a new "diffanchors" option that takes a list of
`{address}`, and a new "diffopt" option value "anchor". Each address
specified will be an anchor, and the user can choose to use any type of
address, including marks, line numbers, or pattern search. Anchors are
sorted by line number in each file, and it's possible to have multiple
anchors on the same line (this is useful when doing multi-buffer diff).
Update documentation to provide examples.
This is similar to Git diff's `--anchored` flag. Other diff tools like
Meld/Araxis Merge also have similar features (called "synchronization
points" or "synchronization links"). We are not using Git/Xdiff's
`--anchored` implementation here because it has a very limited API
(it requires usage of the Patience algorithm, and can only anchor
unique lines that are the same across both files).
Because the user could anchor anywhere, diff anchors could result in
adjacent diff blocks (one block is directly touching another without a
gap), if there is a change right above the anchor point. We don't want
to merge these diff blocks because we want to line up the change at the
anchor. Adjacent diff blocks were first allowed when linematch was
added, but the existing code had a lot of branched paths where
line-matched diff blocks were handled differently. As a part of this
change, refactor them to have a more unified code path that is
generalized enough to handle adjacent diff blocks correctly and without
needing to carve in exceptions all over the place.
closes: #17615
Signed-off-by: Yee Cheng Chin <ychin.git@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: regression when displaying localized percentage position
(after v9.1.1291)
Solution: calculate percentage first (Emir SARI)
Cleanups made in ec032de broke the Turkish percent display, failing to
prepend it properly in cases between 0 and 10. In Turkish, the percent
sign is prepended to the number, so it was displaying it as `% 5`
(should have been `%5`), while displaying numbers bigger than 9 properly.
related: #17597
Signed-off-by: Emir SARI <emir_sari@icloud.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: The 'grepformat' option is global option, but it would be
useful to have it buffer-local, similar to 'errorformat' and
other quickfix related options (Dani Dickstein)
Solution: Add the necessary code to support global-local 'grepformat',
allowing different buffers to parse different grep output
formats (glepnir)
fixes: #17316closes: #17315
Signed-off-by: glepnir <glephunter@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: The check in buf_freeall that restores curwin subtly prevents
leaving an unloaded buffer in a window when reusing curbuf, if
autocommands switch to a different buffer.
Solution: Add a test case that covers this. Also ensure splitting isn't
possible, as that could do the same (Sean Dewar)
closes: #17325
Signed-off-by: Sean Dewar <6256228+seandewar@users.noreply.github.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: buflist_new() leaks ffname and fails to reuse curbuf when
autocommands from buf_freeall change curbuf. Plus, a new
buffer is not allocated in this case, despite what the comment
above claims.
Solution: Remove the condition so ffname is not leaked and so a new
buffer is allocated like before v8.2.4791. It should not be
possible for undo_ftplugin or buf_freeall autocommands to
delete the buffer as they set b_locked, but to stay consistent
with other uses of buf_freeall, guard against that anyway
(Sean Dewar).
Note that buf is set to NULL if it was deleted to guard against the (rare)
possibility of messing up the "buf != curbuf" condition below if a new buffer
happens to be allocated at the same address.
closes: #17319
Signed-off-by: Sean Dewar <6256228+seandewar@users.noreply.github.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: [security]: Possible to open more windows into a closing
buffer without splitting, bypassing existing "b_locked_split"
checks and triggering use-after-free
Solution: Disallow switching to a closing buffer. Editing a closing
buffer (via ":edit", etc.) was fixed in v9.1.0764, but add an
error message and check just "b_locked_split", as "b_locked"
is necessary only when the buffer shouldn't be wiped, and may
be set for buffers that are in-use but not actually closing.
(Sean Dewar)
closes: #17246
Signed-off-by: Sean Dewar <6256228+seandewar@users.noreply.github.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: Cannot define completion triggers and act upon it
Solution: add the new option 'isexpand' and add the complete_match()
function to return the completion matches according to the
'isexpand' setting (glepnir)
Currently, completion trigger position is determined solely by the
'iskeyword' pattern (\k\+$), which causes issues when users need
different completion behaviors - such as triggering after '/' for
comments or '.' for methods. Modifying 'iskeyword' to include these
characters has undesirable side effects on other Vim functionality that
relies on keyword definitions.
Introduce a new buffer-local option 'isexpand' that allows specifying
different completion triggers and add the complete_match() function that
finds the appropriate start column for completion based on these
triggers, scanning backwards from cursor position.
This separation of concerns allows customized completion behavior
without affecting iskeyword-dependent features. The option's
buffer-local nature enables per-filetype completion triggers.
closes: #16716
Signed-off-by: glepnir <glephunter@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: b:undo_ftplugin not executed when re-using buffer
(archy3)
Solution: explicitly execute b:undo_ftplugin in buflist_new() when
re-using the current buffer
fixes: #17113closes: #17133
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: too many strlen() calls in buffer.c
Solution: refactor buffer.c and remove strlen() calls
(John Marriott)
closes: #17063
Signed-off-by: John Marriott <basilisk@internode.on.net>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: Coverity warns about using uninitialized value
(after 9.1.1270).
Solution: Put an empty string in "buf" when allocation fails (zeertzjq).
closes: #17040
Signed-off-by: zeertzjq <zeertzjq@outlook.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: [fifo] is not displayed when editing a fifo
(after v7.4.2189)
Solution: stat the filename and detect the type correctly
fixes: #16702closes: #16705
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: too many strlen() calls in drawscreen.c
Solution: refactor drawscreen.c and remove calls to strlen(),
make get_keymap_str() (in screen.c) return string length
instead of TRUE/FALSE (John Marriott).
Signed-off-by: John Marriott <basilisk@internode.on.net>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: 'findexpr' can't be used for lambads
(Justin Keyes)
Solution: Replace the findexpr option with the findfunc option
(Yegappan Lakshmanan)
related: #15905closes: #15976
Signed-off-by: Yegappan Lakshmanan <yegappan@yahoo.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: tests: no error check when setting global 'cc'
Solution: also parse and check global 'cc' value (Milly)
closes: #15914
Signed-off-by: Milly <milly.ca@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: [security]: use-after-free when closing a buffer
Solution: When splitting the window and editing a new buffer,
check whether the newly to be edited buffer has been marked
for deletion and abort in this case
Github Advisory:
https://github.com/vim/vim/security/advisories/GHSA-rj48-v4mq-j4vg
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: [security]: use-after-free in alist_add()
(SuyueGuo)
Solution: Lock the current window, so that the reference to
the argument list remains valid.
This fixes CVE-2024-43374
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: moving in the buffer list doesn't work as documented
(SenileFelineS)
Solution: Skip non-help buffers, when run from normal buffers, else
only move from help buffers to the next help buffer (LemonBoy)
As explained in the help section for :bnext and :bprev the commands
should jump from help buffers to help buffers (and from regular ones to
regular ones).
fixes: #4478closes: #15198
Signed-off-by: LemonBoy <thatlemon@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: :bwipe doesn't remove file from jumplist and tagstack of other
tabpages. Time complexity of mark_forget_file() is O(n^2) when
removing all entries (after v9.1.0554)
Solution: Use FOR_ALL_TAB_WINDOWS(). Start the loops over the arrays
from the end instead of the start (zeertzjq)
closes: #15199
Signed-off-by: zeertzjq <zeertzjq@outlook.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: :bw leaves jumplist and tagstack data around
(Paul "Joey" Clark)
Solution: Wipe jumplist and tagstack references to the wiped buffer
(LemonBoy)
As documented the :bwipeout command brutally deletes all the references
to the buffer, so let's make it delete all the entries in the jump list
and tag stack referring to the wiped-out buffer.
fixes: #8201closes: #15185
Signed-off-by: LemonBoy <thatlemon@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: Cannot have buffer-local value for 'completeopt'
(Nick Jensen).
Solution: Make 'completeopt' global-local (zeertzjq).
Also for some reason test Test_ColonEight_MultiByte seems to be failing
sporadically now. Let's mark it as flaky.
fixes: #5487closes: #14922
Signed-off-by: zeertzjq <zeertzjq@outlook.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: Filetype may be undetected when a SwapExists autocommand sets
filetype in another buffer.
Solution: Make filetype detection state buffer-specific. Also fix a
similar problem for 'modified' (zeertzjq).
closes: #14344
Signed-off-by: zeertzjq <zeertzjq@outlook.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: More code can use ml_get_buf_len() instead of STRLEN().
Solution: Change more STRLEN() calls to ml_get_buf_len(). Also do not
set ml_line_textlen in ml_replace_len() if "has_props" is set,
because "len_arg" also includes the size of text properties in
that case. (zeertzjq)
closes: #14183
Signed-off-by: zeertzjq <zeertzjq@outlook.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: Cannot keep a buffer focused in a window
(Amit Levy)
Solution: Add the 'winfixbuf' window-local option
(Colin Kennedy)
fixes: #6445closes: #13903
Signed-off-by: Colin Kennedy <colinvfx@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: [security]: autocmd cause use-after-free in set_curbuf()
(kawarimidoll)
Solution: check side-effect of BufLeave autocommand, when the number
of windows changed, close windows containing buffers that will
be wiped, if curbuf changed unexpectedly make sure b_nwindows
is decremented otherwise it cannot be wiped
set_curbuf() already makes some efforts to ensure the BufLeave
autocommands do not cause issues. However there are still 2 issues
that are not taken care of:
1) If a BufLeave autocommand opens a new window containing the same
buffer as that is going got be closed in close_buffer() a bit later,
we suddenly have another window open, containing a free'd buffer. So we
must check if the number of windows changed and if it does (and the
current buffer is going to be wiped (according to the 'bufhidden'
setting), let's immediately close all windows containing the current
buffer using close_windows()
2) If a BufLeave autocommand changes our current buffer (displays it in
the current window), buf->b_nwindow will be incremented. As part of
set_curbuf() we will however enter another buffer soon, which means, the
newly created curbuf will have b_nwindows still have set, even so the
buffer is no longer displayed in a window. This causes later problems,
because it will no longer be possible to wipe such a buffer. So just
before entering the final buffer, check if the curbuf changed when
calling the BufLeave autocommand and if it does (and curbuf is still
valid), decrement curbuf->b_nwindows.
Both issues can be verified using the provided test (however the second
issue only because such an impacted buffer won't be wiped, causing
futher issues in later tests).
fixes: #13839closes: #14104
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: buffer-completion code too complicated and does not always
find all matches (irisjae)
Solution: do not try to anchor pattern to beginning of line or
directory-separator, always return all matches
Note: we are considering the non-fuzzy buffer-matching here.
Currently, the buffer-completion code makes 2 attempts to match a
pattern against the list of available patterns. First try is to match
the pattern and anchor it to either the beginning of the file name or
at a directory-separator (// or \\).
When a match is found, Vim returns the matching buffers and does not try
to find a match anywhere within a buffer name. So if you have opened two
buffers like /tmp/Foobar.c and /tmp/MyFoobar.c using `:b Foo` will only
complete to the first filename, but not the second (the same happens
with `getcompletion('Foo', 'buffer')`).
It may make sense, that completion priorities buffer names at directory
boundaries, but it inconsistent, may cause confusion why a certain
buffer name is not completed when typing `:b Foo<C-D>` which returns
only a single file name and then pressing Enter (to switch to that
buffer), Vim will error with 'E93: More than one match for Foo').
Similar things may happen when wiping the /tmp/Foobar.c pattern and
afterwards the completion starts completing other buffers.
So let's simplify the code and always match the pattern anywhere in the
buffer name, do not try to favor matches at directory boundaries. This
is also simplifies the code a bit, we do not need to run over the list
of buffers several times, but only twice.
fixes#13894closes: #14082
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: duplicate code when cleaning undo stack
Solution: refactor undo cleanup into a single public function
related: #13928
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: E95 is possible if a buffer called "[Command Line]" already
exists when opening the cmdwin. This can also happen if the
cmdwin's buffer could not be deleted when closing.
Solution: Un-name the cmdwin buffer, and give it a special name instead,
similar to what's done for quickfix buffers and for unnamed
prompt and scratch buffers. As a result, BufFilePre/Post are
no longer fired when opening the cmdwin. Add a "command" key
to the dictionary returned by getbufinfo() to differentiate
the cmdwin buffer instead. (Sean Dewar)
NOTE: This is technically a breaking change... maybe this needs a different
solution? (Or maybe this issue can be ignored...)
A GitHub search reveals some plugins expect the old behaviour. However, many of
those plugins also do not seem to account for the string being translated, so
they are subtly broken anyway (not withstanding the fact that you can call any
old buffer "[Command Line]" too...)
closes: #12819
Signed-off-by: Sean Dewar <seandewar@users.noreply.github.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: is*() and to*() function may be unsafe
Solution: Add SAFE_* macros and start using those instead
(Keith Thompson)
Use SAFE_() macros for is*() and to*() functions
The standard is*() and to*() functions declared in <ctype.h> have
undefined behavior for negative arguments other than EOF. If plain char
is signed, passing an unchecked value from argv for from user input
to one of these functions has undefined behavior.
Solution: Add SAFE_*() macros that cast the argument to unsigned char.
Most implementations behave sanely for negative arguments, and most
character values in practice are non-negative, but it's still best
to avoid undefined behavior.
The change from #13347 has been omitted, as this has already been
separately fixed in commit ac709e2fc0
(v9.0.2054)
fixes: #13332closes: #13347
Signed-off-by: Keith Thompson <Keith.S.Thompson@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: Get E304 when using 'cryptmethod' "xchacha20v2". (Steve Mynott)
Solution: Add 4th crypt method to block zero ID check. Avoid syncing a swap
file before reading the file. (closes#12433)
Problem: RedrawingDisabled not used consistently.
Solution: Avoid RedrawingDisabled going negative. Set RedrawingDisabled in
win_split_ins(). (closes#11961)
Problem: Some commands for opening a file don't use 'switchbuf'.
Solution: Use 'switchbuf' for more commands. (Yegappan Lakshmanan,
closes#12383, closes#12381)