Merge remote-tracking branch 'vim/master'

This commit is contained in:
ichizok
2021-06-23 18:27:17 +09:00
70 changed files with 2754 additions and 268 deletions
+6
View File
@@ -3034,6 +3034,8 @@ test_feedinput({string}) none add key sequence to input buffer
test_garbagecollect_now() none free memory right now for testing
test_garbagecollect_soon() none free memory soon for testing
test_getvalue({string}) any get value of an internal variable
test_gui_mouse_event({button}, {row}, {col}, {repeated}, {mods})
none add a mouse event to the input buffer
test_ignore_error({expr}) none ignore a specific error
test_null_blob() Blob null value for testing
test_null_channel() Channel null value for testing
@@ -5853,7 +5855,10 @@ getqflist([{what}]) *getqflist()*
bufname() to get the name
module module name
lnum line number in the buffer (first line is 1)
end_lnum
end of line number if the item is multiline
col column number (first column is 1)
end_col end of column number if the item has range
vcol |TRUE|: "col" is visual column
|FALSE|: "col" is byte index
nr error number
@@ -11983,6 +11988,7 @@ scrollbind Compiled with 'scrollbind' support. (always true)
showcmd Compiled with 'showcmd' support.
signs Compiled with |:sign| support.
smartindent Compiled with 'smartindent' support.
sodium Compiled with libsodium for better crypt support
sound Compiled with sound support, e.g. `sound_playevent()`
spell Compiled with spell checking support |spell|.
startuptime Compiled with |--startuptime| support.
+17
View File
@@ -2399,6 +2399,23 @@ A jump table for the options with a short description can be found at |Q_op|.
you write the file the encrypted bytes will be
different. The whole undo file is encrypted, not just
the pieces of text.
*E1193* *E1194* *E1195* *E1196*
*E1197* *E1198* *E1199* *E1200* *E1201*
xchacha20 XChaCha20 Cipher with Poly1305 Message Authentication
Code. Medium strong till strong encryption.
Encryption is provided by the libsodium library, it
requires Vim to be built with |+sodium|
It adds a seed and a message authentication code (MAC)
to the file. This needs at least a Vim 8.2.3022 to
read the encrypted file.
Encryption of swap files is not supported, therefore
no swap file will be used when xchacha20 encryption is
enabled.
Encryption of undo files is not yet supported,
therefore no undo file will currently be written.
CURRENTLY EXPERIMENTAL: Files written with this method
might have to be read back with the same version of
Vim if the binary format changes later.
You should use "blowfish2", also to re-encrypt older files.
+25 -1
View File
@@ -1,4 +1,4 @@
*testing.txt* For Vim version 8.2. Last change: 2021 Apr 02
*testing.txt* For Vim version 8.2. Last change: 2021 Jun 21
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -78,6 +78,30 @@ test_getvalue({name}) *test_getvalue()*
Can also be used as a |method|: >
GetName()->test_getvalue()
<
*test_gui_mouse_event()*
test_gui_mouse_event({button}, {row}, {col}, {multiclick}, {modifiers})
Inject a mouse button click event. This function works only
when GUI is running.
The supported values for {button} are:
0 right mouse button
1 middle mouse button
2 left mouse button
3 mouse button release
4 scroll wheel down
5 scroll wheel up
6 scroll wheel left
7 scroll wheel right
{row} and {col} specify the location of the mouse click.
To inject a multiclick event, set {multiclick} to 1.
The supported values for {modifiers} are:
4 shift is pressed
8 alt is pressed
16 ctrl is pressed
After injecting the mouse event you probably should call
|feedkeys()| to have them processed, e.g.: >
call feedkeys("y", 'Lx!')
test_ignore_error({expr}) *test_ignore_error()*
Ignore any error containing {expr}. A normal message is given
+1
View File
@@ -1021,6 +1021,7 @@ Testing: *test-functions*
test_garbagecollect_now() free memory right now
test_garbagecollect_soon() set a flag to free memory soon
test_getvalue() get value of an internal variable
test_gui_mouse_event() add a GUI mouse event to the input buffer
test_ignore_error() ignore a specific error message
test_null_blob() return a null Blob
test_null_channel() return a null Channel
+1
View File
@@ -446,6 +446,7 @@ m *+ruby/dyn* Ruby interface |ruby-dynamic| |/dyn|
T *+scrollbind* |'scrollbind'|
B *+signs* |:sign|
N *+smartindent* |'smartindent'|
B *+sodium* compiled with libsodium for better encryption support
B *+sound* |sound_playevent()|, |sound_playfile()| functions, etc.
N *+spell* spell checking support, see |spell|
N *+startuptime* |--startuptime| argument
+3
View File
@@ -322,6 +322,9 @@ MSYS2 has its own git package, and you can also install it via pacman:
$ pacman -S git
For enabling libsodium support, you also need to install the package
$ pacman -S mingw-w64-x86_64-libsodium
2.3. Keep the build environment up-to-date
+13 -2
View File
@@ -41,6 +41,9 @@ DEBUG=no
# set to yes to measure code coverage
COVERAGE=no
# better encryption support using libsodium
#SODIUM=yes
# set to SIZE for size, SPEED for speed, MAXSPEED for maximum optimization
OPTIMIZE=MAXSPEED
@@ -517,6 +520,10 @@ CXXFLAGS = -std=gnu++11
WINDRES_FLAGS =
EXTRA_LIBS =
ifdef SODIUM
DEFINES += -DHAVE_SODIUM
endif
ifdef GETTEXT
DEFINES += -DHAVE_GETTEXT -DHAVE_LOCALE_H
GETTEXTINCLUDE = $(GETTEXT)/include
@@ -660,6 +667,10 @@ DEFINES += -DFEAT_DIRECTX_COLOR_EMOJI
endif
endif
ifeq ($(SODIUM),yes)
SODIUMLIB = -lsodium
endif
# Only allow XPM for a GUI build.
ifeq (yes, $(GUI))
@@ -1064,7 +1075,7 @@ $(EXEOBJC): | $(OUTDIR)
ifeq ($(VIMDLL),yes)
$(TARGET): $(OBJ)
$(LINK) $(CFLAGS) $(LFLAGS) -o $@ $(OBJ) $(LIB) -lole32 -luuid -lgdi32 $(LUA_LIB) $(MZSCHEME_LIBDIR) $(MZSCHEME_LIB) $(PYTHONLIB) $(PYTHON3LIB) $(RUBYLIB)
$(LINK) $(CFLAGS) $(LFLAGS) -o $@ $(OBJ) $(LIB) -lole32 -luuid -lgdi32 $(LUA_LIB) $(MZSCHEME_LIBDIR) $(MZSCHEME_LIB) $(PYTHONLIB) $(PYTHON3LIB) $(RUBYLIB) $(SODIUMLIB)
$(GVIMEXE): $(EXEOBJG) $(VIMDLLBASE).dll
$(CC) -L. $(EXELFLAGS) -mwindows -o $@ $(EXEOBJG) -l$(VIMDLLBASE)
@@ -1073,7 +1084,7 @@ $(VIMEXE): $(EXEOBJC) $(VIMDLLBASE).dll
$(CC) -L. $(EXELFLAGS) -o $@ $(EXEOBJC) -l$(VIMDLLBASE)
else
$(TARGET): $(OBJ)
$(LINK) $(CFLAGS) $(LFLAGS) -o $@ $(OBJ) $(LIB) -lole32 -luuid $(LUA_LIB) $(MZSCHEME_LIBDIR) $(MZSCHEME_LIB) $(PYTHONLIB) $(PYTHON3LIB) $(RUBYLIB)
$(LINK) $(CFLAGS) $(LFLAGS) -o $@ $(OBJ) $(LIB) -lole32 -luuid $(LUA_LIB) $(MZSCHEME_LIBDIR) $(MZSCHEME_LIB) $(PYTHONLIB) $(PYTHON3LIB) $(RUBYLIB) $(SODIUMLIB)
endif
upx: exes
+29 -2
View File
@@ -41,6 +41,13 @@
#
# Sound support: SOUND=yes (default is yes)
#
# Sodium support: SODIUM=[Path to Sodium directory]
# Dynamic built with libsodium
# You need to install the msvc package from
# https://download.libsodium.org/libsodium/releases/
# and package the libsodium.dll with Vim
#
#
# DLL support (EXPERIMENTAL): VIMDLL=yes (default is no)
# Creates vim{32,64}.dll, and stub gvim.exe and vim.exe.
# The shared codes between the GUI and the console are built into
@@ -372,6 +379,26 @@ SOUND = no
! endif
!endif
!ifndef SODIUM
SODIUM = no
!endif
!if "$(SODIUM)" != "no"
! if "$(CPU)" == "AMD64"
SOD_LIB = $(SODIUM)\x64\Release\v140\dynamic
! elseif "$(CPU)" == "i386"
SOD_LIB = $(SODIUM)\Win32\Release\v140\dynamic
! else
SODIUM = no
! endif
!endif
!if "$(SODIUM)" != "no"
SOD_INC = /I "$(SODIUM)\include"
SOD_DEFS = -DFEAT_SODIUM
SOD_LIB = $(SOD_LIB)\libsodium.lib
!endif
!ifndef NETBEANS
NETBEANS = $(GUI)
!endif
@@ -491,7 +518,7 @@ CON_LIB = $(CON_LIB) /DELAYLOAD:comdlg32.dll /DELAYLOAD:ole32.dll DelayImp.lib
CFLAGS = -c /W3 /GF /nologo $(CVARS) -I. -Iproto -DHAVE_PATHDEF -DWIN32 \
$(CSCOPE_DEFS) $(TERM_DEFS) $(SOUND_DEFS) $(NETBEANS_DEFS) $(CHANNEL_DEFS) \
$(NBDEBUG_DEFS) $(XPM_DEFS) \
$(NBDEBUG_DEFS) $(XPM_DEFS) $(SOD_DEFS) $(SOD_INC) \
$(DEFINES) -DWINVER=$(WINVER) -D_WIN32_WINNT=$(WINVER)
#>>>>> end of choices
@@ -1282,7 +1309,7 @@ conflags = $(conflags) /map /mapinfo:lines
LINKARGS1 = $(linkdebug) $(conflags)
LINKARGS2 = $(CON_LIB) $(GUI_LIB) $(NODEFAULTLIB) $(LIBC) $(OLE_LIB) user32.lib \
$(LUA_LIB) $(MZSCHEME_LIB) $(PERL_LIB) $(PYTHON_LIB) $(PYTHON3_LIB) $(RUBY_LIB) \
$(TCL_LIB) $(SOUND_LIB) $(NETBEANS_LIB) $(XPM_LIB) $(LINK_PDB)
$(TCL_LIB) $(SOUND_LIB) $(NETBEANS_LIB) $(XPM_LIB) $(SOD_LIB) $(LINK_PDB)
# Report link time code generation progress if used.
!ifdef NODEBUG
+66
View File
@@ -844,6 +844,7 @@ with_motif_lib
with_tlib
enable_largefile
enable_canberra
enable_libsodium
enable_acl
enable_gpm
enable_sysmouse
@@ -1510,6 +1511,7 @@ Optional Features:
--disable-desktop-database-update update disabled
--disable-largefile omit support for large files
--disable-canberra Do not use libcanberra.
--disable-libsodium Do not use libsodium.
--disable-acl No check for ACL support.
--disable-gpm Don't use gpm (Linux mouse daemon).
--disable-sysmouse Don't use sysmouse (mouse in *BSD console).
@@ -13235,6 +13237,70 @@ rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --enable-libsodium argument" >&5
$as_echo_n "checking --enable-libsodium argument... " >&6; }
# Check whether --enable-libsodium was given.
if test "${enable_libsodium+set}" = set; then :
enableval=$enable_libsodium;
else
enable_libsodium="maybe"
fi
if test "$enable_libsodium" = "maybe"; then
if test "$features" = "big" -o "$features" = "huge"; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: Defaulting to yes" >&5
$as_echo "Defaulting to yes" >&6; }
enable_libsodium="yes"
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: Defaulting to no" >&5
$as_echo "Defaulting to no" >&6; }
enable_libsodium="no"
fi
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_libsodium" >&5
$as_echo "$enable_libsodium" >&6; }
fi
if test "$enable_libsodium" = "yes"; then
if test "x$PKG_CONFIG" != "xno"; then
libsodium_lib=`$PKG_CONFIG --libs libsodium 2>/dev/null`
libsodium_cflags=`$PKG_CONFIG --cflags libsodium 2>/dev/null`
fi
if test "x$libsodium_lib" = "x"; then
libsodium_lib=-lsodium
libsodium_cflags=
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libcanberra" >&5
$as_echo_n "checking for libcanberra... " >&6; }
ac_save_CFLAGS="$CFLAGS"
ac_save_LIBS="$LIBS"
CFLAGS="$CFLAGS $libsodium_cflags"
LIBS="$LIBS $libsodium_lib"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
# include <sodium.h>
int
main ()
{
printf("%d", sodium_init());
;
return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }; $as_echo "#define HAVE_SODIUM 1" >>confdefs.h
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no; try installing libsodium-dev" >&5
$as_echo "no; try installing libsodium-dev" >&6; }; CFLAGS="$ac_save_CFLAGS"; LIBS="$ac_save_LIBS"
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for st_blksize" >&5
$as_echo_n "checking for st_blksize... " >&6; }
+4 -3
View File
@@ -596,7 +596,8 @@ crypt_blowfish_encode(
cryptstate_T *state,
char_u *from,
size_t len,
char_u *to)
char_u *to,
int last UNUSED)
{
bf_state_T *bfs = state->method_state;
size_t i;
@@ -619,7 +620,8 @@ crypt_blowfish_decode(
cryptstate_T *state,
char_u *from,
size_t len,
char_u *to)
char_u *to,
int last UNUSED)
{
bf_state_T *bfs = state->method_state;
size_t i;
@@ -680,5 +682,4 @@ blowfish_self_test(void)
}
return OK;
}
#endif // FEAT_CRYPT
+17 -2
View File
@@ -30,6 +30,7 @@ struct bw_info
int bw_flags; // FIO_ flags
#ifdef FEAT_CRYPT
buf_T *bw_buffer; // buffer being written
int bw_finish; // finish encrypting
#endif
char_u bw_rest[CONV_RESTLEN]; // not converted bytes
int bw_restlen; // nr of bytes in bw_rest[]
@@ -493,14 +494,14 @@ buf_write_bytes(struct bw_info *ip)
if (crypt_works_inplace(ip->bw_buffer->b_cryptstate))
{
# endif
crypt_encode_inplace(ip->bw_buffer->b_cryptstate, buf, len);
crypt_encode_inplace(ip->bw_buffer->b_cryptstate, buf, len, ip->bw_finish);
# ifdef CRYPT_NOT_INPLACE
}
else
{
char_u *outbuf;
len = crypt_encode_alloc(curbuf->b_cryptstate, buf, len, &outbuf);
len = crypt_encode_alloc(curbuf->b_cryptstate, buf, len, &outbuf, ip->bw_finish);
if (len == 0)
return OK; // Crypt layer is buffering, will flush later.
wlen = write_eintr(ip->bw_fd, outbuf, len);
@@ -724,6 +725,7 @@ buf_write(
#endif
#ifdef FEAT_CRYPT
write_info.bw_buffer = buf;
write_info.bw_finish = FALSE;
#endif
// After writing a file changedtick changes but we don't want to display
@@ -2015,6 +2017,13 @@ restore_backup:
++s;
if (++len != bufsize)
continue;
#ifdef FEAT_CRYPT
if (write_info.bw_fd > 0 && lnum == end
&& (write_info.bw_flags & FIO_ENCRYPTED)
&& *buf->b_p_key != NUL && !filtering
&& *ptr == NUL)
write_info.bw_finish = TRUE;
#endif
if (buf_write_bytes(&write_info) == FAIL)
{
end = 0; // write error: break loop
@@ -2118,6 +2127,12 @@ restore_backup:
if (len > 0 && end > 0)
{
write_info.bw_len = len;
#ifdef FEAT_CRYPT
if (write_info.bw_fd > 0 && lnum >= end
&& (write_info.bw_flags & FIO_ENCRYPTED)
&& *buf->b_p_key != NUL && !filtering)
write_info.bw_finish = TRUE;
#endif
if (buf_write_bytes(&write_info) == FAIL)
end = 0; // write error
nchars += len;
+1
View File
@@ -208,6 +208,7 @@
#undef HAVE_STRPTIME
#undef HAVE_STRTOL
#undef HAVE_CANBERRA
#undef HAVE_SODIUM
#undef HAVE_ST_BLKSIZE
#undef HAVE_SYSCONF
#undef HAVE_SYSCTL
+37
View File
@@ -3952,6 +3952,43 @@ if test "$enable_canberra" = "yes"; then
AC_MSG_RESULT(no; try installing libcanberra-dev); CFLAGS="$ac_save_CFLAGS"; LIBS="$ac_save_LIBS")
fi
AC_MSG_CHECKING(--enable-libsodium argument)
AC_ARG_ENABLE(libsodium,
[ --disable-libsodium Do not use libsodium.],
, [enable_libsodium="maybe"])
if test "$enable_libsodium" = "maybe"; then
if test "$features" = "big" -o "$features" = "huge"; then
AC_MSG_RESULT(Defaulting to yes)
enable_libsodium="yes"
else
AC_MSG_RESULT(Defaulting to no)
enable_libsodium="no"
fi
else
AC_MSG_RESULT($enable_libsodium)
fi
if test "$enable_libsodium" = "yes"; then
if test "x$PKG_CONFIG" != "xno"; then
libsodium_lib=`$PKG_CONFIG --libs libsodium 2>/dev/null`
libsodium_cflags=`$PKG_CONFIG --cflags libsodium 2>/dev/null`
fi
if test "x$libsodium_lib" = "x"; then
libsodium_lib=-lsodium
libsodium_cflags=
fi
AC_MSG_CHECKING(for libcanberra)
ac_save_CFLAGS="$CFLAGS"
ac_save_LIBS="$LIBS"
CFLAGS="$CFLAGS $libsodium_cflags"
LIBS="$LIBS $libsodium_lib"
AC_TRY_LINK([
# include <sodium.h>
], [
printf("%d", sodium_init()); ],
AC_MSG_RESULT(yes); AC_DEFINE(HAVE_SODIUM),
AC_MSG_RESULT(no; try installing libsodium-dev); CFLAGS="$ac_save_CFLAGS"; LIBS="$ac_save_LIBS")
fi
dnl fstatfs() can take 2 to 4 arguments, try to use st_blksize if possible
AC_MSG_CHECKING(for st_blksize)
+402 -30
View File
@@ -12,6 +12,10 @@
*/
#include "vim.h"
#ifdef FEAT_SODIUM
# include <sodium.h>
#endif
#if defined(FEAT_CRYPT) || defined(PROTO)
/*
* Optional encryption support.
@@ -33,7 +37,7 @@ typedef struct {
char *name; // encryption name as used in 'cryptmethod'
char *magic; // magic bytes stored in file header
int salt_len; // length of salt, or 0 when not using salt
int seed_len; // length of seed, or 0 when not using salt
int seed_len; // length of seed, or 0 when not using seed
#ifdef CRYPT_NOT_INPLACE
int works_inplace; // encryption/decryption can be done in-place
#endif
@@ -49,16 +53,16 @@ typedef struct {
// Function pointers for encoding/decoding from one buffer into another.
// Optional, however, these or the _buffer ones should be configured.
void (*encode_fn)(cryptstate_T *state, char_u *from, size_t len,
char_u *to);
char_u *to, int last);
void (*decode_fn)(cryptstate_T *state, char_u *from, size_t len,
char_u *to);
char_u *to, int last);
// Function pointers for encoding and decoding, can buffer data if needed.
// Optional (however, these or the above should be configured).
long (*encode_buffer_fn)(cryptstate_T *state, char_u *from, size_t len,
char_u **newptr);
char_u **newptr, int last);
long (*decode_buffer_fn)(cryptstate_T *state, char_u *from, size_t len,
char_u **newptr);
char_u **newptr, int last);
// Function pointers for in-place encoding and decoding, used for
// crypt_*_inplace(). "from" and "to" arguments will be equal.
@@ -68,9 +72,9 @@ typedef struct {
// padding to files).
// This method is used for swap and undo files which have a rigid format.
void (*encode_inplace_fn)(cryptstate_T *state, char_u *p1, size_t len,
char_u *p2);
char_u *p2, int last);
void (*decode_inplace_fn)(cryptstate_T *state, char_u *p1, size_t len,
char_u *p2);
char_u *p2, int last);
} cryptmethod_T;
// index is method_nr of cryptstate_T, CRYPT_M_*
@@ -126,10 +130,41 @@ static cryptmethod_T cryptmethods[CRYPT_M_COUNT] = {
crypt_blowfish_encode, crypt_blowfish_decode,
},
// XChaCha20 using libsodium
{
"xchacha20",
"VimCrypt~04!",
#ifdef FEAT_SODIUM
crypto_pwhash_argon2id_SALTBYTES, // 16
#else
16,
#endif
8,
#ifdef CRYPT_NOT_INPLACE
FALSE,
#endif
FALSE,
NULL,
crypt_sodium_init,
NULL, NULL,
crypt_sodium_buffer_encode, crypt_sodium_buffer_decode,
NULL, NULL,
},
// NOTE: when adding a new method, use some random bytes for the magic key,
// to avoid that a text file is recognized as encrypted.
};
#ifdef FEAT_SODIUM
typedef struct {
size_t count;
unsigned char key[crypto_box_SEEDBYTES];
// 32, same as crypto_secretstream_xchacha20poly1305_KEYBYTES
crypto_secretstream_xchacha20poly1305_state
state;
} sodium_state_T;
#endif
#define CRYPT_MAGIC_LEN 12 // cannot change
static char crypt_magic_head[] = "VimCrypt~";
@@ -215,6 +250,26 @@ crypt_get_header_len(int method_nr)
+ cryptmethods[method_nr].seed_len;
}
/*
* Get maximum crypt method specific length of the file header in bytes.
*/
int
crypt_get_max_header_len()
{
int i;
int max = 0;
int temp = 0;
for (i = 0; i < CRYPT_M_COUNT; ++i)
{
temp = crypt_get_header_len(i);
if (temp > max)
max = temp;
}
return max;
}
/*
* Set the crypt method for buffer "buf" to "method_nr" using the int value as
* returned by crypt_method_nr_from_name().
@@ -260,7 +315,7 @@ crypt_create(
state->method_nr = method_nr;
if (cryptmethods[method_nr].init_fn(
state, key, salt, salt_len, seed, seed_len) == FAIL)
state, key, salt, salt_len, seed, seed_len) == FAIL)
{
vim_free(state);
return NULL;
@@ -365,9 +420,18 @@ crypt_create_for_writing(
// TODO: Should this be crypt method specific? (Probably not worth
// it). sha2_seed is pretty bad for large amounts of entropy, so make
// that into something which is suitable for anything.
sha2_seed(salt, salt_len, seed, seed_len);
#ifdef FEAT_SODIUM
if (sodium_init() >= 0)
{
if (salt_len > 0)
randombytes_buf(salt, salt_len);
if (seed_len > 0)
randombytes_buf(seed, seed_len);
}
else
#endif
sha2_seed(salt, salt_len, seed, seed_len);
}
state = crypt_create(method_nr, key, salt, salt_len, seed, seed_len);
if (state == NULL)
VIM_CLEAR(*header);
@@ -380,7 +444,15 @@ crypt_create_for_writing(
void
crypt_free_state(cryptstate_T *state)
{
vim_free(state->method_state);
#ifdef FEAT_SODIUM
if (state->method_nr == CRYPT_M_SOD)
{
sodium_memzero(state->method_state, sizeof(sodium_state_T));
sodium_free(state->method_state);
}
else
#endif
vim_free(state->method_state);
vim_free(state);
}
@@ -395,21 +467,22 @@ crypt_encode_alloc(
cryptstate_T *state,
char_u *from,
size_t len,
char_u **newptr)
char_u **newptr,
int last)
{
cryptmethod_T *method = &cryptmethods[state->method_nr];
if (method->encode_buffer_fn != NULL)
// Has buffer function, pass through.
return method->encode_buffer_fn(state, from, len, newptr);
return method->encode_buffer_fn(state, from, len, newptr, last);
if (len == 0)
// Not buffering, just return EOF.
return (long)len;
*newptr = alloc(len);
*newptr = alloc(len + 50);
if (*newptr == NULL)
return -1;
method->encode_fn(state, from, len, *newptr);
method->encode_fn(state, from, len, *newptr, last);
return (long)len;
}
@@ -423,13 +496,14 @@ crypt_decode_alloc(
cryptstate_T *state,
char_u *ptr,
long len,
char_u **newptr)
char_u **newptr,
int last)
{
cryptmethod_T *method = &cryptmethods[state->method_nr];
if (method->decode_buffer_fn != NULL)
// Has buffer function, pass through.
return method->decode_buffer_fn(state, ptr, len, newptr);
return method->decode_buffer_fn(state, ptr, len, newptr, last);
if (len == 0)
// Not buffering, just return EOF.
@@ -438,7 +512,7 @@ crypt_decode_alloc(
*newptr = alloc(len);
if (*newptr == NULL)
return -1;
method->decode_fn(state, ptr, len, *newptr);
method->decode_fn(state, ptr, len, *newptr, last);
return len;
}
#endif
@@ -451,9 +525,10 @@ crypt_encode(
cryptstate_T *state,
char_u *from,
size_t len,
char_u *to)
char_u *to,
int last)
{
cryptmethods[state->method_nr].encode_fn(state, from, len, to);
cryptmethods[state->method_nr].encode_fn(state, from, len, to, last);
}
#if 0 // unused
@@ -465,9 +540,10 @@ crypt_decode(
cryptstate_T *state,
char_u *from,
size_t len,
char_u *to)
char_u *to,
int last)
{
cryptmethods[state->method_nr].decode_fn(state, from, len, to);
cryptmethods[state->method_nr].decode_fn(state, from, len, to, last);
}
#endif
@@ -478,9 +554,11 @@ crypt_decode(
crypt_encode_inplace(
cryptstate_T *state,
char_u *buf,
size_t len)
size_t len,
int last)
{
cryptmethods[state->method_nr].encode_inplace_fn(state, buf, len, buf);
cryptmethods[state->method_nr].encode_inplace_fn(state, buf, len,
buf, last);
}
/*
@@ -490,9 +568,11 @@ crypt_encode_inplace(
crypt_decode_inplace(
cryptstate_T *state,
char_u *buf,
size_t len)
size_t len,
int last)
{
cryptmethods[state->method_nr].decode_inplace_fn(state, buf, len, buf);
cryptmethods[state->method_nr].decode_inplace_fn(state, buf, len,
buf, last);
}
/*
@@ -525,6 +605,26 @@ crypt_check_method(int method)
}
}
#ifdef FEAT_SODIUM
static void
crypt_check_swapfile_curbuf(void)
{
int method = crypt_get_method_nr(curbuf);
if (method == CRYPT_M_SOD)
{
// encryption uses padding and MAC, that does not work very well with
// swap and undo files, so disable them
mf_close_file(curbuf, TRUE); // remove the swap file
set_option_value((char_u *)"swf", 0, NULL, OPT_LOCAL);
#ifdef FEAT_PERSISTENT_UNDO
set_option_value((char_u *)"udf", 0, NULL, OPT_LOCAL);
#endif
msg_scroll = TRUE;
msg(_("Note: Encryption of swapfile not supported, disabling swap- and undofile"));
}
}
#endif
void
crypt_check_current_method(void)
{
@@ -576,6 +676,9 @@ crypt_get_key(
set_option_value((char_u *)"key", 0L, p1, OPT_LOCAL);
crypt_free_key(p1);
p1 = curbuf->b_p_key;
#ifdef FEAT_SODIUM
crypt_check_swapfile_curbuf();
#endif
}
break;
}
@@ -583,10 +686,13 @@ crypt_get_key(
}
// since the user typed this, no need to wait for return
if (msg_didout)
msg_putchar('\n');
need_wait_return = FALSE;
msg_didout = FALSE;
if (crypt_get_method_nr(curbuf) != CRYPT_M_SOD)
{
if (msg_didout)
msg_putchar('\n');
need_wait_return = FALSE;
msg_didout = FALSE;
}
crypt_free_key(p2);
return p1;
@@ -610,4 +716,270 @@ crypt_append_msg(
}
}
int
crypt_sodium_init(
cryptstate_T *state UNUSED,
char_u *key UNUSED,
char_u *salt UNUSED,
int salt_len UNUSED,
char_u *seed UNUSED,
int seed_len UNUSED)
{
# ifdef FEAT_SODIUM
// crypto_box_SEEDBYTES == crypto_secretstream_xchacha20poly1305_KEYBYTES
unsigned char dkey[crypto_box_SEEDBYTES]; // 32
sodium_state_T *sd_state;
if (sodium_init() < 0)
return FAIL;
sd_state = (sodium_state_T *)sodium_malloc(sizeof(sodium_state_T));
sodium_memzero(sd_state, sizeof(sodium_state_T));
// derive a key from the password
if (crypto_pwhash(dkey, sizeof(dkey), (const char *)key, STRLEN(key), salt,
crypto_pwhash_OPSLIMIT_INTERACTIVE, crypto_pwhash_MEMLIMIT_INTERACTIVE,
crypto_pwhash_ALG_DEFAULT) != 0)
{
// out of memory
sodium_free(sd_state);
return FAIL;
}
memcpy(sd_state->key, dkey, crypto_box_SEEDBYTES);
sd_state->count = 0;
state->method_state = sd_state;
return OK;
# else
emsg(e_libsodium_not_built_in);
return FAIL;
# endif
}
/*
* Encrypt "from[len]" into "to[len]".
* "from" and "to" can be equal to encrypt in place.
* Call needs to ensure that there is enough space in to (for the header)
*/
#if 0 // Currently unused
void
crypt_sodium_encode(
cryptstate_T *state UNUSED,
char_u *from UNUSED,
size_t len UNUSED,
char_u *to UNUSED,
int last UNUSED)
{
# ifdef FEAT_SODIUM
// crypto_box_SEEDBYTES == crypto_secretstream_xchacha20poly1305_KEYBYTES
sodium_state_T *sod_st = state->method_state;
unsigned char tag = last
? crypto_secretstream_xchacha20poly1305_TAG_FINAL : 0;
if (sod_st->count == 0)
{
if (len <= crypto_secretstream_xchacha20poly1305_HEADERBYTES)
{
emsg(e_libsodium_cannot_encrypt_header);
return;
}
crypto_secretstream_xchacha20poly1305_init_push(&sod_st->state,
to, sod_st->key);
to += crypto_secretstream_xchacha20poly1305_HEADERBYTES;
}
if (sod_st->count && len <= crypto_secretstream_xchacha20poly1305_ABYTES)
{
emsg(e_libsodium_cannot_encrypt_buffer);
return;
}
crypto_secretstream_xchacha20poly1305_push(&sod_st->state, to, NULL,
from, len, NULL, 0, tag);
sod_st->count++;
# endif
}
#endif
/*
* Decrypt "from[len]" into "to[len]".
* "from" and "to" can be equal to encrypt in place.
*/
#if 0 // Currently unused
void
crypt_sodium_decode(
cryptstate_T *state UNUSED,
char_u *from UNUSED,
size_t len UNUSED,
char_u *to UNUSED,
int last UNUSED)
{
# ifdef FEAT_SODIUM
// crypto_box_SEEDBYTES == crypto_secretstream_xchacha20poly1305_KEYBYTES
sodium_state_T *sod_st = state->method_state;
unsigned char tag;
unsigned long long buf_len;
char_u *p1 = from;
char_u *p2 = to;
char_u *buf_out;
if (sod_st->count == 0
&& len <= crypto_secretstream_xchacha20poly1305_HEADERBYTES)
{
emsg(e_libsodium_cannot_decrypt_header);
return;
}
buf_out = (char_u *)alloc(len);
if (buf_out == NULL)
{
emsg(e_libsodium_cannot_allocate_buffer);
return;
}
if (sod_st->count == 0)
{
if (crypto_secretstream_xchacha20poly1305_init_pull(
&sod_st->state, from, sod_st->key) != 0)
{
emsg(e_libsodium_decryption_failed_header_incomplete);
goto fail;
}
from += crypto_secretstream_xchacha20poly1305_HEADERBYTES;
len -= crypto_secretstream_xchacha20poly1305_HEADERBYTES;
if (p1 == p2)
to += crypto_secretstream_xchacha20poly1305_HEADERBYTES;
}
if (sod_st->count && len <= crypto_secretstream_xchacha20poly1305_ABYTES)
{
emsg(e_libsodium_cannot_decrypt_buffer);
goto fail;
}
if (crypto_secretstream_xchacha20poly1305_pull(&sod_st->state,
buf_out, &buf_len, &tag, from, len, NULL, 0) != 0)
{
emsg(e_libsodium_decryption_failed);
goto fail;
}
sod_st->count++;
if (tag == crypto_secretstream_xchacha20poly1305_TAG_FINAL && !last)
{
emsg(e_libsodium_decryption_failed_premature);
goto fail;
}
if (p1 == p2)
mch_memmove(p2, buf_out, buf_len);
fail:
vim_free(buf_out);
# endif
}
#endif
/*
* Encrypt "from[len]" into "to[len]".
* "from" and "to" can be equal to encrypt in place.
*/
long
crypt_sodium_buffer_encode(
cryptstate_T *state UNUSED,
char_u *from UNUSED,
size_t len UNUSED,
char_u **buf_out UNUSED,
int last UNUSED)
{
# ifdef FEAT_SODIUM
// crypto_box_SEEDBYTES == crypto_secretstream_xchacha20poly1305_KEYBYTES
unsigned long long out_len;
char_u *ptr;
unsigned char tag = last
? crypto_secretstream_xchacha20poly1305_TAG_FINAL : 0;
int length;
sodium_state_T *sod_st = state->method_state;
int first = (sod_st->count == 0);
length = (int)len + crypto_secretstream_xchacha20poly1305_ABYTES
+ (first ? crypto_secretstream_xchacha20poly1305_HEADERBYTES : 0);
*buf_out = alloc_clear(length);
if (*buf_out == NULL)
{
emsg(e_libsodium_cannot_allocate_buffer);
return -1;
}
ptr = *buf_out;
if (first)
{
crypto_secretstream_xchacha20poly1305_init_push(&sod_st->state,
ptr, sod_st->key);
ptr += crypto_secretstream_xchacha20poly1305_HEADERBYTES;
}
crypto_secretstream_xchacha20poly1305_push(&sod_st->state, ptr,
&out_len, from, len, NULL, 0, tag);
sod_st->count++;
return out_len + (first
? crypto_secretstream_xchacha20poly1305_HEADERBYTES : 0);
# else
return -1;
# endif
}
/*
* Decrypt "from[len]" into "to[len]".
* "from" and "to" can be equal to encrypt in place.
*/
long
crypt_sodium_buffer_decode(
cryptstate_T *state UNUSED,
char_u *from UNUSED,
size_t len UNUSED,
char_u **buf_out UNUSED,
int last UNUSED)
{
# ifdef FEAT_SODIUM
// crypto_box_SEEDBYTES == crypto_secretstream_xchacha20poly1305_KEYBYTES
sodium_state_T *sod_st = state->method_state;
unsigned char tag;
unsigned long long out_len;
*buf_out = alloc_clear(len);
if (*buf_out == NULL)
{
emsg(e_libsodium_cannot_allocate_buffer);
return -1;
}
if (sod_st->count == 0)
{
if (crypto_secretstream_xchacha20poly1305_init_pull(&sod_st->state,
from, sod_st->key) != 0)
{
emsg(e_libsodium_decryption_failed_header_incomplete);
return -1;
}
from += crypto_secretstream_xchacha20poly1305_HEADERBYTES;
len -= crypto_secretstream_xchacha20poly1305_HEADERBYTES;
sod_st->count++;
}
if (crypto_secretstream_xchacha20poly1305_pull(&sod_st->state,
*buf_out, &out_len, &tag, from, len, NULL, 0) != 0)
{
emsg(e_libsodium_decryption_failed);
return -1;
}
if (tag == crypto_secretstream_xchacha20poly1305_TAG_FINAL && !last)
emsg(e_libsodium_decryption_failed_premature);
return (long) out_len;
# else
return -1;
# endif
}
#endif // FEAT_CRYPT
+4 -2
View File
@@ -114,7 +114,8 @@ crypt_zip_encode(
cryptstate_T *state,
char_u *from,
size_t len,
char_u *to)
char_u *to,
int last UNUSED)
{
zip_state_T *zs = state->method_state;
size_t i;
@@ -137,7 +138,8 @@ crypt_zip_decode(
cryptstate_T *state,
char_u *from,
size_t len,
char_u *to)
char_u *to,
int last UNUSED)
{
zip_state_T *zs = state->method_state;
size_t i;
+1 -1
View File
@@ -606,7 +606,7 @@ dbg_parsearg(
}
if (bp->dbg_type == DBG_FUNC)
bp->dbg_name = vim_strsave(p);
bp->dbg_name = vim_strsave(STRNCMP(p, "g:", 2) == 0 ? p + 2 : p);
else if (here)
bp->dbg_name = vim_strsave(curbuf->b_ffname);
else if (bp->dbg_type == DBG_EXPR)
+3 -2
View File
@@ -1121,8 +1121,9 @@ win_line(
int t;
// like rl_mirror(), but keep the space at the end
p2 = skiptowhite(extra) - 1;
for (p1 = extra; p1 < p2; ++p1, --p2)
p2 = skipwhite(extra);
p2 = skiptowhite(p2) - 1;
for (p1 = skipwhite(extra); p1 < p2; ++p1, --p2)
{
t = *p1;
*p1 = *p2;
+19
View File
@@ -427,3 +427,22 @@ EXTERN char e_call_to_function_that_failed_to_compile_str[]
INIT(= N_("E1191: Call to function that failed to compile: %s"));
EXTERN char e_empty_function_name[]
INIT(= N_("E1192: Empty function name"));
// libsodium
EXTERN char e_libsodium_not_built_in[]
INIT(= N_("E1193: cryptmethod xchacha20 not built into this Vim"));
EXTERN char e_libsodium_cannot_encrypt_header[]
INIT(= N_("E1194: Cannot encrypt header, not enough space"));
EXTERN char e_libsodium_cannot_encrypt_buffer[]
INIT(= N_("E1195: Cannot encrypt buffer, not enough space"));
EXTERN char e_libsodium_cannot_decrypt_header[]
INIT(= N_("E1196: Cannot decrypt header, not enough space"));
EXTERN char e_libsodium_cannot_allocate_buffer[]
INIT(= N_("E1197: Cannot allocate_buffer for encryption"));
EXTERN char e_libsodium_decryption_failed_header_incomplete[]
INIT(= N_("E1198: Decryption failed: Header incomplete!"));
EXTERN char e_libsodium_cannot_decrypt_buffer[]
INIT(= N_("E1199: Cannot decrypt buffer, not enough space"));
EXTERN char e_libsodium_decryption_failed[]
INIT(= N_("E1200: Decryption failed!"));
EXTERN char e_libsodium_decryption_failed_premature[]
INIT(= N_("E1201: Decryption failed: pre-mature end of file!"));
+10 -2
View File
@@ -2218,12 +2218,15 @@ eval0(
int did_emsg_before = did_emsg;
int called_emsg_before = called_emsg;
int flags = evalarg == NULL ? 0 : evalarg->eval_flags;
int end_error = FALSE;
p = skipwhite(arg);
ret = eval1(&p, rettv, evalarg);
p = skipwhite(p);
if (ret == FAIL || !ends_excmd2(arg, p))
if (ret != FAIL)
end_error = !ends_excmd2(arg, p);
if (ret == FAIL || end_error)
{
if (ret != FAIL)
clear_tv(rettv);
@@ -2238,7 +2241,12 @@ eval0(
&& called_emsg == called_emsg_before
&& (flags & EVAL_CONSTANT) == 0
&& (!in_vim9script() || !vim9_bad_comment(p)))
semsg(_(e_invexpr2), arg);
{
if (end_error)
semsg(_(e_trailing_arg), p);
else
semsg(_(e_invexpr2), arg);
}
// Some of the expression may not have been consumed. Do not check for
// a next command to avoid more errors, unless "|" is following, which
+100 -65
View File
@@ -301,6 +301,27 @@ arg_list_or_blob(type_T *type, argcontext_T *context)
return FAIL;
}
/*
* Check "type" is a string or a list of strings.
*/
static int
arg_string_or_list(type_T *type, argcontext_T *context)
{
if (type->tt_type == VAR_ANY || type->tt_type == VAR_STRING)
return OK;
if (type->tt_type != VAR_LIST)
{
arg_type_mismatch(&t_string, type, context->arg_idx + 1);
return FAIL;
}
if (type->tt_member->tt_type == VAR_ANY
|| type->tt_member->tt_type == VAR_STRING)
return OK;
arg_type_mismatch(&t_list_string, type, context->arg_idx + 1);
return FAIL;
}
/*
* Check "type" is a list or a dict.
*/
@@ -382,11 +403,16 @@ arg_extend3(type_T *type, argcontext_T *context)
* Lists of functions that check the argument types of a builtin function.
*/
argcheck_T arg1_string[] = {arg_string};
argcheck_T arg3_string_nr_bool[] = {arg_string, arg_number, arg_bool};
argcheck_T arg1_number[] = {arg_number};
argcheck_T arg1_float_or_nr[] = {arg_float_or_nr};
argcheck_T arg2_float_or_nr[] = {arg_float_or_nr, arg_float_or_nr};
argcheck_T arg2_number[] = {arg_number, arg_number};
argcheck_T arg2_listblob_item[] = {arg_list_or_blob, arg_item_of_prev};
argcheck_T arg2_execute[] = {arg_string_or_list, arg_string};
argcheck_T arg23_extend[] = {arg_list_or_dict, arg_same_as_prev, arg_extend3};
argcheck_T arg23_extendnew[] = {arg_list_or_dict, arg_same_struct_as_prev, arg_extend3};
argcheck_T arg3_string[] = {arg_string, arg_string, arg_string};
argcheck_T arg3_string_nr_bool[] = {arg_string, arg_number, arg_bool};
argcheck_T arg3_insert[] = {arg_list_or_blob, arg_item_of_prev, arg_number};
/*
@@ -648,25 +674,25 @@ static funcentry_T global_functions[] =
{
{"abs", 1, 1, FEARG_1, arg1_float_or_nr,
ret_any, FLOAT_FUNC(f_abs)},
{"acos", 1, 1, FEARG_1, NULL,
{"acos", 1, 1, FEARG_1, arg1_float_or_nr,
ret_float, FLOAT_FUNC(f_acos)},
{"add", 2, 2, FEARG_1, NULL /* arg2_listblob_item */,
ret_first_arg, f_add},
{"and", 2, 2, FEARG_1, NULL,
{"and", 2, 2, FEARG_1, arg2_number,
ret_number, f_and},
{"append", 2, 2, FEARG_2, NULL,
ret_number_bool, f_append},
{"appendbufline", 3, 3, FEARG_3, NULL,
ret_number_bool, f_appendbufline},
{"argc", 0, 1, 0, NULL,
{"argc", 0, 1, 0, arg1_number,
ret_number, f_argc},
{"argidx", 0, 0, 0, NULL,
ret_number, f_argidx},
{"arglistid", 0, 2, 0, NULL,
{"arglistid", 0, 2, 0, arg2_number,
ret_number, f_arglistid},
{"argv", 0, 2, 0, NULL,
{"argv", 0, 2, 0, arg2_number,
ret_argv, f_argv},
{"asin", 1, 1, FEARG_1, NULL,
{"asin", 1, 1, FEARG_1, arg1_float_or_nr,
ret_float, FLOAT_FUNC(f_asin)},
{"assert_beeps", 1, 2, FEARG_1, NULL,
ret_number_bool, f_assert_beeps},
@@ -694,9 +720,9 @@ static funcentry_T global_functions[] =
ret_number_bool, f_assert_report},
{"assert_true", 1, 2, FEARG_1, NULL,
ret_number_bool, f_assert_true},
{"atan", 1, 1, FEARG_1, NULL,
{"atan", 1, 1, FEARG_1, arg1_float_or_nr,
ret_float, FLOAT_FUNC(f_atan)},
{"atan2", 2, 2, FEARG_1, NULL,
{"atan2", 2, 2, FEARG_1, arg2_float_or_nr,
ret_float, FLOAT_FUNC(f_atan2)},
{"balloon_gettext", 0, 0, 0, NULL,
ret_string,
@@ -758,7 +784,7 @@ static funcentry_T global_functions[] =
ret_number, f_byteidxcomp},
{"call", 2, 3, FEARG_1, NULL,
ret_any, f_call},
{"ceil", 1, 1, FEARG_1, NULL,
{"ceil", 1, 1, FEARG_1, arg1_float_or_nr,
ret_float, FLOAT_FUNC(f_ceil)},
{"ch_canread", 1, 1, FEARG_1, NULL,
ret_number_bool, JOB_FUNC(f_ch_canread)},
@@ -810,7 +836,7 @@ static funcentry_T global_functions[] =
ret_string, f_chdir},
{"cindent", 1, 1, FEARG_1, NULL,
ret_number, f_cindent},
{"clearmatches", 0, 1, FEARG_1, NULL,
{"clearmatches", 0, 1, FEARG_1, arg1_number,
ret_void, f_clearmatches},
{"col", 1, 1, FEARG_1, NULL,
ret_number, f_col},
@@ -826,9 +852,9 @@ static funcentry_T global_functions[] =
ret_number, f_confirm},
{"copy", 1, 1, FEARG_1, NULL,
ret_first_arg, f_copy},
{"cos", 1, 1, FEARG_1, NULL,
{"cos", 1, 1, FEARG_1, arg1_float_or_nr,
ret_float, FLOAT_FUNC(f_cos)},
{"cosh", 1, 1, FEARG_1, NULL,
{"cosh", 1, 1, FEARG_1, arg1_float_or_nr,
ret_float, FLOAT_FUNC(f_cosh)},
{"count", 2, 4, FEARG_1, NULL,
ret_number, f_count},
@@ -836,7 +862,7 @@ static funcentry_T global_functions[] =
ret_number, f_cscope_connection},
{"cursor", 1, 3, FEARG_1, NULL,
ret_number, f_cursor},
{"debugbreak", 1, 1, FEARG_1, NULL,
{"debugbreak", 1, 1, FEARG_1, arg1_number,
ret_number,
#ifdef MSWIN
f_debugbreak
@@ -870,13 +896,13 @@ static funcentry_T global_functions[] =
ret_number_bool, f_eventhandler},
{"executable", 1, 1, FEARG_1, NULL,
ret_number, f_executable},
{"execute", 1, 2, FEARG_1, NULL,
{"execute", 1, 2, FEARG_1, arg2_execute,
ret_string, f_execute},
{"exepath", 1, 1, FEARG_1, NULL,
ret_string, f_exepath},
{"exists", 1, 1, FEARG_1, NULL,
ret_number_bool, f_exists},
{"exp", 1, 1, FEARG_1, NULL,
{"exp", 1, 1, FEARG_1, arg1_float_or_nr,
ret_float, FLOAT_FUNC(f_exp)},
{"expand", 1, 3, FEARG_1, NULL,
ret_any, f_expand},
@@ -904,11 +930,11 @@ static funcentry_T global_functions[] =
ret_list_any, f_flatten},
{"flattennew", 1, 2, FEARG_1, NULL,
ret_list_any, f_flattennew},
{"float2nr", 1, 1, FEARG_1, NULL,
{"float2nr", 1, 1, FEARG_1, arg1_float_or_nr,
ret_number, FLOAT_FUNC(f_float2nr)},
{"floor", 1, 1, FEARG_1, NULL,
{"floor", 1, 1, FEARG_1, arg1_float_or_nr,
ret_float, FLOAT_FUNC(f_floor)},
{"fmod", 2, 2, FEARG_1, NULL,
{"fmod", 2, 2, FEARG_1, arg2_float_or_nr,
ret_float, FLOAT_FUNC(f_fmod)},
{"fnameescape", 1, 1, FEARG_1, NULL,
ret_string, f_fnameescape},
@@ -964,11 +990,11 @@ static funcentry_T global_functions[] =
ret_string, f_getcmdwintype},
{"getcompletion", 2, 3, FEARG_1, NULL,
ret_list_string, f_getcompletion},
{"getcurpos", 0, 1, FEARG_1, NULL,
{"getcurpos", 0, 1, FEARG_1, arg1_number,
ret_list_number, f_getcurpos},
{"getcursorcharpos", 0, 1, FEARG_1, NULL,
{"getcursorcharpos", 0, 1, FEARG_1, arg1_number,
ret_list_number, f_getcursorcharpos},
{"getcwd", 0, 2, FEARG_1, NULL,
{"getcwd", 0, 2, FEARG_1, arg2_number,
ret_string, f_getcwd},
{"getenv", 1, 1, FEARG_1, NULL,
ret_any, f_getenv},
@@ -984,7 +1010,7 @@ static funcentry_T global_functions[] =
ret_string, f_getftype},
{"getimstatus", 0, 0, 0, NULL,
ret_number_bool, f_getimstatus},
{"getjumplist", 0, 2, FEARG_1, NULL,
{"getjumplist", 0, 2, FEARG_1, arg2_number,
ret_list_any, f_getjumplist},
{"getline", 1, 2, FEARG_1, NULL,
ret_f_getline, f_getline},
@@ -992,7 +1018,7 @@ static funcentry_T global_functions[] =
ret_list_or_dict_1, f_getloclist},
{"getmarklist", 0, 1, FEARG_1, NULL,
ret_list_dict_any, f_getmarklist},
{"getmatches", 0, 1, 0, NULL,
{"getmatches", 0, 1, 0, arg1_number,
ret_list_dict_any, f_getmatches},
{"getmousepos", 0, 0, 0, NULL,
ret_dict_number, f_getmousepos},
@@ -1008,19 +1034,19 @@ static funcentry_T global_functions[] =
ret_dict_any, f_getreginfo},
{"getregtype", 0, 1, FEARG_1, NULL,
ret_string, f_getregtype},
{"gettabinfo", 0, 1, FEARG_1, NULL,
{"gettabinfo", 0, 1, FEARG_1, arg1_number,
ret_list_dict_any, f_gettabinfo},
{"gettabvar", 2, 3, FEARG_1, NULL,
ret_any, f_gettabvar},
{"gettabwinvar", 3, 4, FEARG_1, NULL,
ret_any, f_gettabwinvar},
{"gettagstack", 0, 1, FEARG_1, NULL,
{"gettagstack", 0, 1, FEARG_1, arg1_number,
ret_dict_any, f_gettagstack},
{"gettext", 1, 1, FEARG_1, NULL,
ret_string, f_gettext},
{"getwininfo", 0, 1, FEARG_1, NULL,
{"getwininfo", 0, 1, FEARG_1, arg1_number,
ret_list_dict_any, f_getwininfo},
{"getwinpos", 0, 1, FEARG_1, NULL,
{"getwinpos", 0, 1, FEARG_1, arg1_number,
ret_list_number, f_getwinpos},
{"getwinposx", 0, 0, 0, NULL,
ret_number, f_getwinposx},
@@ -1038,7 +1064,7 @@ static funcentry_T global_functions[] =
ret_number_bool, f_has},
{"has_key", 2, 2, FEARG_1, NULL,
ret_number_bool, f_has_key},
{"haslocaldir", 0, 2, FEARG_1, NULL,
{"haslocaldir", 0, 2, FEARG_1, arg2_number,
ret_number, f_haslocaldir},
{"hasmapto", 1, 3, FEARG_1, NULL,
ret_number_bool, f_hasmapto},
@@ -1082,15 +1108,15 @@ static funcentry_T global_functions[] =
ret_first_arg, f_insert},
{"interrupt", 0, 0, 0, NULL,
ret_void, f_interrupt},
{"invert", 1, 1, FEARG_1, NULL,
{"invert", 1, 1, FEARG_1, arg1_number,
ret_number, f_invert},
{"isdirectory", 1, 1, FEARG_1, NULL,
ret_number_bool, f_isdirectory},
{"isinf", 1, 1, FEARG_1, NULL,
{"isinf", 1, 1, FEARG_1, arg1_float_or_nr,
ret_number, MATH_FUNC(f_isinf)},
{"islocked", 1, 1, FEARG_1, NULL,
ret_number_bool, f_islocked},
{"isnan", 1, 1, FEARG_1, NULL,
{"isnan", 1, 1, FEARG_1, arg1_float_or_nr,
ret_number_bool, MATH_FUNC(f_isnan)},
{"items", 1, 1, FEARG_1, NULL,
ret_list_any, f_items},
@@ -1138,13 +1164,13 @@ static funcentry_T global_functions[] =
ret_number, f_listener_add},
{"listener_flush", 0, 1, FEARG_1, NULL,
ret_void, f_listener_flush},
{"listener_remove", 1, 1, FEARG_1, NULL,
{"listener_remove", 1, 1, FEARG_1, arg1_number,
ret_number_bool, f_listener_remove},
{"localtime", 0, 0, 0, NULL,
ret_number, f_localtime},
{"log", 1, 1, FEARG_1, NULL,
{"log", 1, 1, FEARG_1, arg1_float_or_nr,
ret_float, FLOAT_FUNC(f_log)},
{"log10", 1, 1, FEARG_1, NULL,
{"log10", 1, 1, FEARG_1, arg1_float_or_nr,
ret_float, FLOAT_FUNC(f_log10)},
{"luaeval", 1, 2, FEARG_1, NULL,
ret_any,
@@ -1170,9 +1196,9 @@ static funcentry_T global_functions[] =
ret_number, f_matchadd},
{"matchaddpos", 2, 5, FEARG_1, NULL,
ret_number, f_matchaddpos},
{"matcharg", 1, 1, FEARG_1, NULL,
{"matcharg", 1, 1, FEARG_1, arg1_number,
ret_list_string, f_matcharg},
{"matchdelete", 1, 2, FEARG_1, NULL,
{"matchdelete", 1, 2, FEARG_1, arg2_number,
ret_number_bool, f_matchdelete},
{"matchend", 2, 4, FEARG_1, NULL,
ret_number, f_matchend},
@@ -1214,7 +1240,7 @@ static funcentry_T global_functions[] =
ret_number, f_nextnonblank},
{"nr2char", 1, 2, FEARG_1, NULL,
ret_string, f_nr2char},
{"or", 2, 2, FEARG_1, NULL,
{"or", 2, 2, FEARG_1, arg2_number,
ret_number, f_or},
{"pathshorten", 1, 2, FEARG_1, NULL,
ret_string, f_pathshorten},
@@ -1268,7 +1294,7 @@ static funcentry_T global_functions[] =
ret_void, PROP_FUNC(f_popup_settext)},
{"popup_show", 1, 1, FEARG_1, NULL,
ret_void, PROP_FUNC(f_popup_show)},
{"pow", 2, 2, FEARG_1, NULL,
{"pow", 2, 2, FEARG_1, arg2_float_or_nr,
ret_float, FLOAT_FUNC(f_pow)},
{"prevnonblank", 1, 1, FEARG_1, NULL,
ret_number, f_prevnonblank},
@@ -1376,7 +1402,7 @@ static funcentry_T global_functions[] =
ret_string, f_resolve},
{"reverse", 1, 1, FEARG_1, NULL,
ret_first_arg, f_reverse},
{"round", 1, 1, FEARG_1, NULL,
{"round", 1, 1, FEARG_1, arg1_float_or_nr,
ret_float, FLOAT_FUNC(f_round)},
{"rubyeval", 1, 1, FEARG_1, NULL,
ret_any,
@@ -1386,11 +1412,11 @@ static funcentry_T global_functions[] =
NULL
#endif
},
{"screenattr", 2, 2, FEARG_1, NULL,
{"screenattr", 2, 2, FEARG_1, arg2_number,
ret_number, f_screenattr},
{"screenchar", 2, 2, FEARG_1, NULL,
{"screenchar", 2, 2, FEARG_1, arg2_number,
ret_number, f_screenchar},
{"screenchars", 2, 2, FEARG_1, NULL,
{"screenchars", 2, 2, FEARG_1, arg2_number,
ret_list_number, f_screenchars},
{"screencol", 0, 0, 0, NULL,
ret_number, f_screencol},
@@ -1398,7 +1424,7 @@ static funcentry_T global_functions[] =
ret_dict_number, f_screenpos},
{"screenrow", 0, 0, 0, NULL,
ret_number, f_screenrow},
{"screenstring", 2, 2, FEARG_1, NULL,
{"screenstring", 2, 2, FEARG_1, arg2_number,
ret_string, f_screenstring},
{"search", 1, 5, FEARG_1, NULL,
ret_number, f_search},
@@ -1426,7 +1452,7 @@ static funcentry_T global_functions[] =
ret_number_bool, f_setcharpos},
{"setcharsearch", 1, 1, FEARG_1, NULL,
ret_void, f_setcharsearch},
{"setcmdpos", 1, 1, FEARG_1, NULL,
{"setcmdpos", 1, 1, FEARG_1, arg1_number,
ret_number_bool, f_setcmdpos},
{"setcursorcharpos", 1, 3, FEARG_1, NULL,
ret_number_bool, f_setcursorcharpos},
@@ -1464,7 +1490,7 @@ static funcentry_T global_functions[] =
},
{"shellescape", 1, 2, FEARG_1, NULL,
ret_string, f_shellescape},
{"shiftwidth", 0, 1, FEARG_1, NULL,
{"shiftwidth", 0, 1, FEARG_1, arg1_number,
ret_number, f_shiftwidth},
{"sign_define", 1, 2, FEARG_1, NULL,
ret_any, SIGN_FUNC(f_sign_define)},
@@ -1486,9 +1512,9 @@ static funcentry_T global_functions[] =
ret_list_number, SIGN_FUNC(f_sign_unplacelist)},
{"simplify", 1, 1, FEARG_1, NULL,
ret_string, f_simplify},
{"sin", 1, 1, FEARG_1, NULL,
{"sin", 1, 1, FEARG_1, arg1_float_or_nr,
ret_float, FLOAT_FUNC(f_sin)},
{"sinh", 1, 1, FEARG_1, NULL,
{"sinh", 1, 1, FEARG_1, arg1_float_or_nr,
ret_float, FLOAT_FUNC(f_sinh)},
{"slice", 2, 3, FEARG_1, NULL,
ret_first_arg, f_slice},
@@ -1510,7 +1536,7 @@ static funcentry_T global_functions[] =
ret_list_string, f_spellsuggest},
{"split", 1, 3, FEARG_1, NULL,
ret_list_string, f_split},
{"sqrt", 1, 1, FEARG_1, NULL,
{"sqrt", 1, 1, FEARG_1, arg1_float_or_nr,
ret_float, FLOAT_FUNC(f_sqrt)},
{"srand", 0, 1, FEARG_1, NULL,
ret_list_number, f_srand},
@@ -1594,9 +1620,9 @@ static funcentry_T global_functions[] =
ret_list_string, f_tagfiles},
{"taglist", 1, 2, FEARG_1, NULL,
ret_list_dict_any, f_taglist},
{"tan", 1, 1, FEARG_1, NULL,
{"tan", 1, 1, FEARG_1, arg1_float_or_nr,
ret_float, FLOAT_FUNC(f_tan)},
{"tanh", 1, 1, FEARG_1, NULL,
{"tanh", 1, 1, FEARG_1, arg1_float_or_nr,
ret_float, FLOAT_FUNC(f_tanh)},
{"tempname", 0, 0, 0, NULL,
ret_string, f_tempname},
@@ -1674,6 +1700,8 @@ static funcentry_T global_functions[] =
ret_void, f_test_garbagecollect_soon},
{"test_getvalue", 1, 1, FEARG_1, NULL,
ret_number, f_test_getvalue},
{"test_gui_mouse_event", 5, 5, 0, NULL,
ret_void, f_test_gui_mouse_event},
{"test_ignore_error", 1, 1, FEARG_1, NULL,
ret_void, f_test_ignore_error},
{"test_null_blob", 0, 0, 0, NULL,
@@ -1726,15 +1754,15 @@ static funcentry_T global_functions[] =
ret_void, TIMER_FUNC(f_timer_stop)},
{"timer_stopall", 0, 0, 0, NULL,
ret_void, TIMER_FUNC(f_timer_stopall)},
{"tolower", 1, 1, FEARG_1, NULL,
{"tolower", 1, 1, FEARG_1, arg1_string,
ret_string, f_tolower},
{"toupper", 1, 1, FEARG_1, NULL,
{"toupper", 1, 1, FEARG_1, arg1_string,
ret_string, f_toupper},
{"tr", 3, 3, FEARG_1, NULL,
{"tr", 3, 3, FEARG_1, arg3_string,
ret_string, f_tr},
{"trim", 1, 3, FEARG_1, NULL,
ret_string, f_trim},
{"trunc", 1, 1, FEARG_1, NULL,
{"trunc", 1, 1, FEARG_1, arg1_float_or_nr,
ret_float, FLOAT_FUNC(f_trunc)},
{"type", 1, 1, FEARG_1, NULL,
ret_number, f_type},
@@ -1760,27 +1788,27 @@ static funcentry_T global_functions[] =
ret_list_number, f_win_findbuf},
{"win_getid", 0, 2, FEARG_1, NULL,
ret_number, f_win_getid},
{"win_gettype", 0, 1, FEARG_1, NULL,
{"win_gettype", 0, 1, FEARG_1, arg1_number,
ret_string, f_win_gettype},
{"win_gotoid", 1, 1, FEARG_1, NULL,
{"win_gotoid", 1, 1, FEARG_1, arg1_number,
ret_number_bool, f_win_gotoid},
{"win_id2tabwin", 1, 1, FEARG_1, NULL,
{"win_id2tabwin", 1, 1, FEARG_1, arg1_number,
ret_list_number, f_win_id2tabwin},
{"win_id2win", 1, 1, FEARG_1, NULL,
{"win_id2win", 1, 1, FEARG_1, arg1_number,
ret_number, f_win_id2win},
{"win_screenpos", 1, 1, FEARG_1, NULL,
{"win_screenpos", 1, 1, FEARG_1, arg1_number,
ret_list_number, f_win_screenpos},
{"win_splitmove", 2, 3, FEARG_1, NULL,
ret_number_bool, f_win_splitmove},
{"winbufnr", 1, 1, FEARG_1, NULL,
{"winbufnr", 1, 1, FEARG_1, arg1_number,
ret_number, f_winbufnr},
{"wincol", 0, 0, 0, NULL,
ret_number, f_wincol},
{"windowsversion", 0, 0, 0, NULL,
ret_string, f_windowsversion},
{"winheight", 1, 1, FEARG_1, NULL,
{"winheight", 1, 1, FEARG_1, arg1_number,
ret_number, f_winheight},
{"winlayout", 0, 1, FEARG_1, NULL,
{"winlayout", 0, 1, FEARG_1, arg1_number,
ret_list_any, f_winlayout},
{"winline", 0, 0, 0, NULL,
ret_number, f_winline},
@@ -1792,13 +1820,13 @@ static funcentry_T global_functions[] =
ret_void, f_winrestview},
{"winsaveview", 0, 0, 0, NULL,
ret_dict_number, f_winsaveview},
{"winwidth", 1, 1, FEARG_1, NULL,
{"winwidth", 1, 1, FEARG_1, arg1_number,
ret_number, f_winwidth},
{"wordcount", 0, 0, 0, NULL,
ret_dict_number, f_wordcount},
{"writefile", 2, 3, FEARG_1, NULL,
ret_number_bool, f_writefile},
{"xor", 2, 2, FEARG_1, NULL,
{"xor", 2, 2, FEARG_1, arg2_number,
ret_number, f_xor},
};
@@ -5091,6 +5119,13 @@ f_has(typval_T *argvars, typval_T *rettv)
1
#else
0
#endif
},
{"sodium",
#ifdef FEAT_SODIUM
1
#else
0
#endif
},
{"sound",
+17 -4
View File
@@ -3643,6 +3643,17 @@ skip_substitute(char_u *start, int delimiter)
return p;
}
static int
check_regexp_delim(int c)
{
if (isalpha(c))
{
emsg(_("E146: Regular expressions can't be delimited by letters"));
return FAIL;
}
return OK;
}
/*
* Perform a substitution from line eap->line1 to line eap->line2 using the
* command pointed to by eap->arg which should be of the form:
@@ -3705,11 +3716,9 @@ ex_substitute(exarg_T *eap)
&& vim_strchr((char_u *)"0123456789cegriIp|\"", *cmd) == NULL)
{
// don't accept alphanumeric for separator
if (isalpha(*cmd))
{
emsg(_("E146: Regular expressions can't be delimited by letters"));
if (check_regexp_delim(*cmd) == FAIL)
return;
}
/*
* undocumented vi feature:
* "\/sub/" and "\?sub?" use last used search pattern (almost like
@@ -4909,6 +4918,10 @@ ex_global(exarg_T *eap)
emsg(_("E148: Regular expression missing from global"));
return;
}
else if (check_regexp_delim(*cmd) == FAIL)
{
return;
}
else
{
delim = *cmd; // get the delimiter
+11 -5
View File
@@ -3491,6 +3491,8 @@ find_ex_command(
// can't be an assignment.
if (*eap->cmd == '[')
{
char_u *eq;
p = to_name_const_end(eap->cmd);
if (p == eap->cmd && *p == '[')
{
@@ -3499,12 +3501,19 @@ find_ex_command(
p = skip_var_list(eap->cmd, TRUE, &count, &semicolon, TRUE);
}
if (p == NULL || p == eap->cmd || *skipwhite(p) != '=')
eq = p;
if (eq != NULL)
{
eq = skipwhite(eq);
if (vim_strchr((char_u *)"+-*/%", *eq) != NULL)
++eq;
}
if (p == NULL || p == eap->cmd || *eq != '=')
{
eap->cmdidx = CMD_eval;
return eap->cmd;
}
if (p > eap->cmd && *skipwhite(p) == '=')
if (p > eap->cmd && *eq == '=')
{
eap->cmdidx = CMD_var;
return eap->cmd;
@@ -4529,9 +4538,6 @@ invalid_range(exarg_T *eap)
#endif
break;
case ADDR_UNSIGNED:
if (eap->line2 < 0)
return _(e_invrange);
break;
case ADDR_NONE:
// Will give an error elsewhere.
break;
+7
View File
@@ -596,6 +596,13 @@
# define FEAT_SOUND_CANBERRA
#endif
/*
* libsodium - add cryptography support
*/
#if defined(HAVE_SODIUM) && defined(FEAT_BIG)
# define FEAT_SODIUM
#endif
// There are two ways to use XPM.
#if (defined(HAVE_XM_XPMP_H) && defined(FEAT_GUI_MOTIF)) \
|| defined(HAVE_X11_XPM_H)
+40 -2
View File
@@ -13,6 +13,10 @@
#include "vim.h"
#ifdef FEAT_SODIUM
# include <sodium.h>
#endif
#if defined(__TANDEM)
# include <limits.h> // for SSIZE_MAX
#endif
@@ -148,6 +152,8 @@ readfile(
char_u *p;
off_T filesize = 0;
int skip_read = FALSE;
off_T filesize_disk = 0; // file size read from disk
off_T filesize_count = 0; // counter
#ifdef FEAT_CRYPT
char_u *cryptkey = NULL;
int did_ask_for_key = FALSE;
@@ -215,6 +221,7 @@ readfile(
int using_b_ffname;
int using_b_fname;
static char *msg_is_a_directory = N_("is a directory");
int eof;
au_did_filetype = FALSE; // reset before triggering any autocommands
@@ -405,6 +412,7 @@ readfile(
{
buf_store_time(curbuf, &st, fname);
curbuf->b_mtime_read = curbuf->b_mtime;
filesize_disk = st.st_size;
#ifdef UNIX
/*
* Use the protection bits of the original file for the swap file.
@@ -1080,6 +1088,7 @@ retry:
{
linerest = 0;
filesize = 0;
filesize_count = 0;
skip_count = lines_to_skip;
read_count = lines_to_read;
conv_restlen = 0;
@@ -1204,6 +1213,7 @@ retry:
* Read bytes from curbuf. Used for converting text read
* from stdin.
*/
eof = FALSE;
if (read_buf_lnum > from)
size = 0;
else
@@ -1252,6 +1262,7 @@ retry:
if (!curbuf->b_p_eol)
--tlen;
size = tlen;
eof = TRUE;
break;
}
}
@@ -1263,7 +1274,23 @@ retry:
/*
* Read bytes from the file.
*/
# ifdef FEAT_SODIUM
// Let the crypt layer work with a buffer size of 8192
if (filesize == 0)
// set size to 8K + Sodium Crypt Metadata
size = WRITEBUFSIZE + crypt_get_max_header_len()
+ crypto_secretstream_xchacha20poly1305_HEADERBYTES
+ crypto_secretstream_xchacha20poly1305_ABYTES;
else if (filesize > 0 && (curbuf->b_cryptstate != NULL &&
curbuf->b_cryptstate->method_nr == CRYPT_M_SOD))
size = WRITEBUFSIZE + crypto_secretstream_xchacha20poly1305_ABYTES;
# endif
eof = size;
size = read_eintr(fd, ptr, size);
filesize_count += size;
// hit end of file
eof = (size < eof || filesize_count == filesize_disk);
}
#ifdef FEAT_CRYPT
@@ -1285,7 +1312,8 @@ retry:
if (crypt_works_inplace(curbuf->b_cryptstate))
{
# endif
crypt_decode_inplace(curbuf->b_cryptstate, ptr, size);
crypt_decode_inplace(curbuf->b_cryptstate, ptr,
size, eof);
# ifdef CRYPT_NOT_INPLACE
}
else
@@ -1294,8 +1322,16 @@ retry:
int decrypted_size;
decrypted_size = crypt_decode_alloc(
curbuf->b_cryptstate, ptr, size, &newptr);
curbuf->b_cryptstate, ptr, size,
&newptr, eof);
if (decrypted_size < 0)
{
// error message already given
error = TRUE;
vim_free(newptr);
break;
}
// If the crypt layer is buffering, not producing
// anything yet, need to read more.
if (decrypted_size == 0)
@@ -1325,6 +1361,7 @@ retry:
if (newptr != NULL)
mch_memmove(new_buffer + linerest, newptr,
decrypted_size);
vim_free(newptr);
}
if (new_buffer != NULL)
@@ -1334,6 +1371,7 @@ retry:
new_buffer = NULL;
line_start = buffer;
ptr = buffer + linerest;
real_size = size;
}
size = decrypted_size;
}
+3
View File
@@ -418,6 +418,9 @@ EXTERN type_T t_blob INIT6(VAR_BLOB, 0, 0, TTFLAG_STATIC, NULL, NULL);
EXTERN type_T t_job INIT6(VAR_JOB, 0, 0, TTFLAG_STATIC, NULL, NULL);
EXTERN type_T t_channel INIT6(VAR_CHANNEL, 0, 0, TTFLAG_STATIC, NULL, NULL);
// Special value used for @#.
EXTERN type_T t_number_or_string INIT6(VAR_STRING, 0, 0, TTFLAG_STATIC, NULL, NULL);
EXTERN type_T t_func_unknown INIT6(VAR_FUNC, -1, 0, TTFLAG_STATIC, &t_unknown, NULL);
EXTERN type_T t_func_void INIT6(VAR_FUNC, -1, 0, TTFLAG_STATIC, &t_void, NULL);
EXTERN type_T t_func_any INIT6(VAR_FUNC, -1, 0, TTFLAG_STATIC, &t_any, NULL);
+31 -8
View File
@@ -48,6 +48,11 @@
# include <time.h>
#endif
// for randombytes_buf
#ifdef FEAT_SODIUM
# include <sodium.h>
#endif
#if defined(SASC) || defined(__amigaos4__)
# include <proto/dos.h> // for Open() and Close()
#endif
@@ -64,12 +69,14 @@ typedef struct pointer_entry PTR_EN; // block/line-count pair
#define BLOCK0_ID1_C0 'c' // block 0 id 1 'cm' 0
#define BLOCK0_ID1_C1 'C' // block 0 id 1 'cm' 1
#define BLOCK0_ID1_C2 'd' // block 0 id 1 'cm' 2
#define BLOCK0_ID1_C3 'S' // block 0 id 1 'cm' 3 - but not actually used
#if defined(FEAT_CRYPT)
static int id1_codes[] = {
BLOCK0_ID1_C0, // CRYPT_M_ZIP
BLOCK0_ID1_C1, // CRYPT_M_BF
BLOCK0_ID1_C2, // CRYPT_M_BF2
BLOCK0_ID1_C3, // CRYPT_M_SOD - Unused!
};
#endif
@@ -426,11 +433,15 @@ ml_set_mfp_crypt(buf_T *buf)
{
int method_nr = crypt_get_method_nr(buf);
if (method_nr > CRYPT_M_ZIP)
if (method_nr > CRYPT_M_ZIP && method_nr < CRYPT_M_SOD)
{
// Generate a seed and store it in the memfile.
sha2_seed(buf->b_ml.ml_mfp->mf_seed, MF_SEED_LEN, NULL, 0);
}
#ifdef FEAT_SODIUM
else if (method_nr == CRYPT_M_SOD)
randombytes_buf(buf->b_ml.ml_mfp->mf_seed, MF_SEED_LEN);
#endif
}
}
@@ -447,7 +458,7 @@ ml_set_b0_crypt(buf_T *buf, ZERO_BL *b0p)
int method_nr = crypt_get_method_nr(buf);
b0p->b0_id[1] = id1_codes[method_nr];
if (method_nr > CRYPT_M_ZIP)
if (method_nr > CRYPT_M_ZIP && method_nr < CRYPT_M_SOD)
{
// Generate a seed and store it in block 0 and in the memfile.
sha2_seed(&b0p->b0_seed, MF_SEED_LEN, NULL, 0);
@@ -482,10 +493,18 @@ ml_set_crypt_key(
int top;
int old_method;
if (mfp == NULL)
if (mfp == NULL || mfp->mf_fd < 0)
return; // no memfile yet, nothing to do
old_method = crypt_method_nr_from_name(old_cm);
// Swapfile encryption not supported by XChaCha20
if (crypt_get_method_nr(buf) == CRYPT_M_SOD && *buf->b_p_key != NUL)
{
// close the swapfile
mf_close_file(buf, TRUE);
buf->b_p_swf = FALSE;
return;
}
// First make sure the swapfile is in a consistent state, using the old
// key and method.
{
@@ -911,7 +930,8 @@ ml_check_b0_id(ZERO_BL *b0p)
|| (b0p->b0_id[1] != BLOCK0_ID1
&& b0p->b0_id[1] != BLOCK0_ID1_C0
&& b0p->b0_id[1] != BLOCK0_ID1_C1
&& b0p->b0_id[1] != BLOCK0_ID1_C2)
&& b0p->b0_id[1] != BLOCK0_ID1_C2
&& b0p->b0_id[1] != BLOCK0_ID1_C3)
)
return FAIL;
return OK;
@@ -2402,7 +2422,9 @@ ml_sync_all(int check_file, int check_char)
FOR_ALL_BUFFERS(buf)
{
if (buf->b_ml.ml_mfp == NULL || buf->b_ml.ml_mfp->mf_fname == NULL)
if (buf->b_ml.ml_mfp == NULL
|| buf->b_ml.ml_mfp->mf_fname == NULL
|| buf->b_ml.ml_mfp->mf_fd < 0)
continue; // no file
ml_flush_line(buf); // flush buffered line
@@ -5320,7 +5342,8 @@ ml_encrypt_data(
mch_memmove(new_data, dp, head_end - (char_u *)dp);
// Encrypt the text.
crypt_encode(state, text_start, text_len, new_data + dp->db_txt_start);
crypt_encode(state, text_start, text_len, new_data + dp->db_txt_start,
FALSE);
crypt_free_state(state);
// Clear the gap.
@@ -5360,7 +5383,7 @@ ml_decrypt_data(
if (state != NULL)
{
// Decrypt the text in place.
crypt_decode_inplace(state, text_start, text_len);
crypt_decode_inplace(state, text_start, text_len, FALSE);
crypt_free_state(state);
}
}
@@ -5407,7 +5430,7 @@ ml_crypt_prepare(memfile_T *mfp, off_T offset, int reading)
// of the block for the salt.
vim_snprintf((char *)salt, sizeof(salt), "%ld", (long)offset);
return crypt_create(method_nr, key, salt, (int)STRLEN(salt),
seed, MF_SEED_LEN);
seed, MF_SEED_LEN);
}
#endif
+8 -3
View File
@@ -1324,9 +1324,10 @@ do_set(
// remember character after option name
afterchar = arg[len];
// skip white space, allow ":set ai ?"
while (VIM_ISWHITE(arg[len]))
++len;
if (!in_vim9script())
// skip white space, allow ":set ai ?", ":set hlsearch !"
while (VIM_ISWHITE(arg[len]))
++len;
adding = FALSE;
prepending = FALSE;
@@ -2734,6 +2735,10 @@ set_bool_option(
|| (opt_flags & OPT_GLOBAL) || opt_flags == 0)
&& !curbufIsChanged() && curbuf->b_ml.ml_mfp != NULL)
{
#ifdef FEAT_CRYPT
if (crypt_get_method_nr(curbuf) == CRYPT_M_SOD)
continue;
#endif
u_compute_hash(hash);
u_read_undo(NULL, hash, curbuf->b_fname);
}
+5 -1
View File
@@ -24,7 +24,11 @@ static char *(p_bo_values[]) = {"all", "backspace", "cursor", "complete",
static char *(p_nf_values[]) = {"bin", "octal", "hex", "alpha", "unsigned", NULL};
static char *(p_ff_values[]) = {FF_UNIX, FF_DOS, FF_MAC, NULL};
#ifdef FEAT_CRYPT
static char *(p_cm_values[]) = {"zip", "blowfish", "blowfish2", NULL};
static char *(p_cm_values[]) = {"zip", "blowfish", "blowfish2",
# ifdef FEAT_SODIUM
"xchacha20",
# endif
NULL};
#endif
static char *(p_cmp_values[]) = {"internal", "keepascii", NULL};
static char *(p_dy_values[]) = {"lastline", "truncate", "uhex", NULL};
+2 -2
View File
@@ -1,6 +1,6 @@
/* blowfish.c */
void crypt_blowfish_encode(cryptstate_T *state, char_u *from, size_t len, char_u *to);
void crypt_blowfish_decode(cryptstate_T *state, char_u *from, size_t len, char_u *to);
void crypt_blowfish_encode(cryptstate_T *state, char_u *from, size_t len, char_u *to, int last);
void crypt_blowfish_decode(cryptstate_T *state, char_u *from, size_t len, char_u *to, int last);
int crypt_blowfish_init(cryptstate_T *state, char_u *key, char_u *salt, int salt_len, char_u *seed, int seed_len);
int blowfish_self_test(void);
/* vim: set ft=c : */
+10 -3
View File
@@ -1,9 +1,11 @@
/* crypt.c */
int crypt_method_nr_from_name(char_u *name);
int crypt_method_nr_from_magic(char *ptr, int len);
int crypt_works_inplace(cryptstate_T *state);
int crypt_get_method_nr(buf_T *buf);
int crypt_whole_undofile(int method_nr);
int crypt_get_header_len(int method_nr);
int crypt_get_max_header_len(void);
void crypt_set_cm_option(buf_T *buf, int method_nr);
int crypt_self_test(void);
cryptstate_T *crypt_create(int method_nr, char_u *key, char_u *salt, int salt_len, char_u *seed, int seed_len);
@@ -11,12 +13,17 @@ cryptstate_T *crypt_create_from_header(int method_nr, char_u *key, char_u *heade
cryptstate_T *crypt_create_from_file(FILE *fp, char_u *key);
cryptstate_T *crypt_create_for_writing(int method_nr, char_u *key, char_u **header, int *header_len);
void crypt_free_state(cryptstate_T *state);
void crypt_encode(cryptstate_T *state, char_u *from, size_t len, char_u *to);
void crypt_encode_inplace(cryptstate_T *state, char_u *buf, size_t len);
void crypt_decode_inplace(cryptstate_T *state, char_u *buf, size_t len);
long crypt_encode_alloc(cryptstate_T *state, char_u *from, size_t len, char_u **newptr, int last);
long crypt_decode_alloc(cryptstate_T *state, char_u *ptr, long len, char_u **newptr, int last);
void crypt_encode(cryptstate_T *state, char_u *from, size_t len, char_u *to, int last);
void crypt_encode_inplace(cryptstate_T *state, char_u *buf, size_t len, int last);
void crypt_decode_inplace(cryptstate_T *state, char_u *buf, size_t len, int last);
void crypt_free_key(char_u *key);
void crypt_check_method(int method);
void crypt_check_current_method(void);
char_u *crypt_get_key(int store, int twice);
void crypt_append_msg(buf_T *buf);
int crypt_sodium_init(cryptstate_T *state, char_u *key, char_u *salt, int salt_len, char_u *seed, int seed_len);
long crypt_sodium_buffer_encode(cryptstate_T *state, char_u *from, size_t len, char_u **buf_out, int last);
long crypt_sodium_buffer_decode(cryptstate_T *state, char_u *from, size_t len, char_u **buf_out, int last);
/* vim: set ft=c : */
+2 -2
View File
@@ -1,5 +1,5 @@
/* crypt_zip.c */
int crypt_zip_init(cryptstate_T *state, char_u *key, char_u *salt, int salt_len, char_u *seed, int seed_len);
void crypt_zip_encode(cryptstate_T *state, char_u *from, size_t len, char_u *to);
void crypt_zip_decode(cryptstate_T *state, char_u *from, size_t len, char_u *to);
void crypt_zip_encode(cryptstate_T *state, char_u *from, size_t len, char_u *to, int last);
void crypt_zip_decode(cryptstate_T *state, char_u *from, size_t len, char_u *to, int last);
/* vim: set ft=c : */
+1
View File
@@ -34,5 +34,6 @@ void f_test_unknown(typval_T *argvars, typval_T *rettv);
void f_test_void(typval_T *argvars, typval_T *rettv);
void f_test_scrollbar(typval_T *argvars, typval_T *rettv);
void f_test_setmouse(typval_T *argvars, typval_T *rettv);
void f_test_gui_mouse_event(typval_T *argvars, typval_T *rettv);
void f_test_settime(typval_T *argvars, typval_T *rettv);
/* vim: set ft=c : */
+81 -22
View File
@@ -30,13 +30,16 @@ struct qfline_S
qfline_T *qf_next; // pointer to next error in the list
qfline_T *qf_prev; // pointer to previous error in the list
linenr_T qf_lnum; // line number where the error occurred
linenr_T qf_end_lnum; // line number when the error has range or zero
int qf_fnum; // file number for the line
int qf_col; // column where the error occurred
int qf_end_col; // column when the error has range or zero
int qf_nr; // error number
char_u *qf_module; // module name for this error
char_u *qf_pattern; // search pattern for the error
char_u *qf_text; // description of the error
char_u qf_viscol; // set to TRUE if qf_col is screen column
char_u qf_viscol; // set to TRUE if qf_col and qf_end_col is
// screen column
char_u qf_cleared; // set to TRUE if line has been deleted
char_u qf_type; // type of the error (mostly 'E'); 1 for
// :helpgrep
@@ -165,7 +168,7 @@ static efm_T *fmt_start = NULL; // cached across qf_parse_line() calls
static callback_T qftf_cb;
static void qf_new_list(qf_info_T *qi, char_u *qf_title);
static int qf_add_entry(qf_list_T *qfl, char_u *dir, char_u *fname, char_u *module, int bufnum, char_u *mesg, long lnum, int col, int vis_col, char_u *pattern, int nr, int type, int valid);
static int qf_add_entry(qf_list_T *qfl, char_u *dir, char_u *fname, char_u *module, int bufnum, char_u *mesg, long lnum, long end_lnum, int col, int end_col, int vis_col, char_u *pattern, int nr, int type, int valid);
static void qf_free(qf_list_T *qfl);
static char_u *qf_types(int, int);
static int qf_get_fnum(qf_list_T *qfl, char_u *, char_u *);
@@ -174,6 +177,7 @@ static char_u *qf_pop_dir(struct dir_stack_T **);
static char_u *qf_guess_filepath(qf_list_T *qfl, char_u *);
static void qf_jump_newwin(qf_info_T *qi, int dir, int errornr, int forceit, int newwin);
static void qf_fmt_text(char_u *text, char_u *buf, int bufsize);
static void qf_range_text(qfline_T *qfp, char_u *buf, int bufsize);
static int qf_win_pos_update(qf_info_T *qi, int old_qf_index);
static win_T *qf_find_win(qf_info_T *qi);
static buf_T *qf_find_buf(qf_info_T *qi);
@@ -899,7 +903,9 @@ typedef struct {
char_u *errmsg;
int errmsglen;
long lnum;
long end_lnum;
int col;
int end_col;
char_u use_viscol;
char_u *pattern;
int enr;
@@ -1235,7 +1241,9 @@ qf_parse_get_fields(
if (!qf_multiscan)
fields->errmsg[0] = NUL;
fields->lnum = 0;
fields->end_lnum = 0;
fields->col = 0;
fields->end_col = 0;
fields->use_viscol = FALSE;
fields->enr = -1;
fields->type = 0;
@@ -1630,7 +1638,9 @@ qf_init_process_nextline(
0,
fields->errmsg,
fields->lnum,
fields->end_lnum,
fields->col,
fields->end_col,
fields->use_viscol,
fields->pattern,
fields->enr,
@@ -2053,7 +2063,9 @@ qf_add_entry(
int bufnum, // buffer number or zero
char_u *mesg, // message
long lnum, // line number
long end_lnum, // line number for end
int col, // column
int end_col, // column for end
int vis_col, // using visual column
char_u *pattern, // search pattern
int nr, // error number
@@ -2082,7 +2094,9 @@ qf_add_entry(
return QF_FAIL;
}
qfp->qf_lnum = lnum;
qfp->qf_end_lnum = end_lnum;
qfp->qf_col = col;
qfp->qf_end_col = end_col;
qfp->qf_viscol = vis_col;
if (pattern == NULL || *pattern == NUL)
qfp->qf_pattern = NULL;
@@ -2239,7 +2253,9 @@ copy_loclist_entries(qf_list_T *from_qfl, qf_list_T *to_qfl)
0,
from_qfp->qf_text,
from_qfp->qf_lnum,
from_qfp->qf_end_lnum,
from_qfp->qf_col,
from_qfp->qf_end_col,
from_qfp->qf_viscol,
from_qfp->qf_pattern,
from_qfp->qf_nr,
@@ -3555,11 +3571,8 @@ qf_list_entry(qfline_T *qfp, int qf_idx, int cursel)
msg_puts_attr(":", qfSepAttr);
if (qfp->qf_lnum == 0)
IObuff[0] = NUL;
else if (qfp->qf_col == 0)
sprintf((char *)IObuff, "%ld", qfp->qf_lnum);
else
sprintf((char *)IObuff, "%ld col %d",
qfp->qf_lnum, qfp->qf_col);
qf_range_text(qfp, IObuff, IOSIZE);
sprintf((char *)IObuff + STRLEN(IObuff), "%s",
(char *)qf_types(qfp->qf_type, qfp->qf_nr));
msg_puts_attr((char *)IObuff, qfLineAttr);
@@ -3685,6 +3698,37 @@ qf_fmt_text(char_u *text, char_u *buf, int bufsize)
buf[i] = NUL;
}
/*
* Range information from lnum, col, end_lnum, and end_col.
* Put the result in "buf[bufsize]".
*/
static void
qf_range_text(qfline_T *qfp, char_u *buf, int bufsize)
{
int len;
vim_snprintf((char *)buf, bufsize, "%ld", qfp->qf_lnum);
len = (int)STRLEN(buf);
if (qfp->qf_end_lnum > 0 && qfp->qf_lnum != qfp->qf_end_lnum)
{
vim_snprintf((char *)buf + len, bufsize - len,
"-%ld", qfp->qf_end_lnum);
len += (int)STRLEN(buf + len);
}
if (qfp->qf_col > 0)
{
vim_snprintf((char *)buf + len, bufsize - len, " col %d", qfp->qf_col);
len += (int)STRLEN(buf + len);
if (qfp->qf_end_col > 0 && qfp->qf_col != qfp->qf_end_col)
{
vim_snprintf((char *)buf + len, bufsize - len,
"-%d", qfp->qf_end_col);
len += (int)STRLEN(buf + len);
}
}
buf[len] = NUL;
}
/*
* Display information (list number, list size and the title) about a
* quickfix/location list.
@@ -4473,7 +4517,17 @@ qf_update_buffer(qf_info_T *qi, qfline_T *old_last)
int qf_winid = 0;
if (IS_LL_STACK(qi))
qf_winid = curwin->w_id;
{
if (curwin->w_llist == qi)
win = curwin;
else
{
win = qf_find_win_with_loclist(qi);
if (win == NULL)
return;
}
qf_winid = win->w_id;
}
if (old_last == NULL)
// set curwin/curbuf to buf and save a few things
@@ -4555,17 +4609,9 @@ qf_buf_add_line(
if (qfp->qf_lnum > 0)
{
vim_snprintf((char *)IObuff + len, IOSIZE - len, "%ld",
qfp->qf_lnum);
qf_range_text(qfp, IObuff + len, IOSIZE - len);
len += (int)STRLEN(IObuff + len);
if (qfp->qf_col > 0)
{
vim_snprintf((char *)IObuff + len, IOSIZE - len,
" col %d", qfp->qf_col);
len += (int)STRLEN(IObuff + len);
}
vim_snprintf((char *)IObuff + len, IOSIZE - len, "%s",
(char *)qf_types(qfp->qf_type, qfp->qf_nr));
len += (int)STRLEN(IObuff + len);
@@ -5943,7 +5989,9 @@ vgr_match_buflines(
ml_get_buf(buf,
regmatch->startpos[0].lnum + lnum, FALSE),
regmatch->startpos[0].lnum + lnum,
regmatch->endpos[0].lnum + lnum,
regmatch->startpos[0].col + 1,
regmatch->endpos[0].col + 1,
FALSE, // vis_col
NULL, // search pattern
0, // nr
@@ -5986,7 +6034,9 @@ vgr_match_buflines(
duplicate_name ? 0 : buf->b_fnum,
str,
lnum,
0,
matches[0] + col + 1,
0,
FALSE, // vis_col
NULL, // search pattern
0, // nr
@@ -6616,10 +6666,12 @@ get_qfline_items(qfline_T *qfp, list_T *list)
buf[0] = qfp->qf_type;
buf[1] = NUL;
if (dict_add_number(dict, "bufnr", (long)bufnum) == FAIL
|| dict_add_number(dict, "lnum", (long)qfp->qf_lnum) == FAIL
|| dict_add_number(dict, "col", (long)qfp->qf_col) == FAIL
|| dict_add_number(dict, "vcol", (long)qfp->qf_viscol) == FAIL
|| dict_add_number(dict, "nr", (long)qfp->qf_nr) == FAIL
|| dict_add_number(dict, "lnum", (long)qfp->qf_lnum) == FAIL
|| dict_add_number(dict, "end_lnum", (long)qfp->qf_end_lnum) == FAIL
|| dict_add_number(dict, "col", (long)qfp->qf_col) == FAIL
|| dict_add_number(dict, "end_col", (long)qfp->qf_end_col) == FAIL
|| dict_add_number(dict, "vcol", (long)qfp->qf_viscol) == FAIL
|| dict_add_number(dict, "nr", (long)qfp->qf_nr) == FAIL
|| dict_add_string(dict, "module", qfp->qf_module) == FAIL
|| dict_add_string(dict, "pattern", qfp->qf_pattern) == FAIL
|| dict_add_string(dict, "text", qfp->qf_text) == FAIL
@@ -7133,8 +7185,8 @@ qf_add_entry_from_dict(
{
static int did_bufnr_emsg;
char_u *filename, *module, *pattern, *text, *type;
int bufnum, valid, status, col, vcol, nr;
long lnum;
int bufnum, valid, status, col, end_col, vcol, nr;
long lnum, end_lnum;
if (first_entry)
did_bufnr_emsg = FALSE;
@@ -7143,7 +7195,9 @@ qf_add_entry_from_dict(
module = dict_get_string(d, (char_u *)"module", TRUE);
bufnum = (int)dict_get_number(d, (char_u *)"bufnr");
lnum = (int)dict_get_number(d, (char_u *)"lnum");
end_lnum = (int)dict_get_number(d, (char_u *)"end_lnum");
col = (int)dict_get_number(d, (char_u *)"col");
end_col = (int)dict_get_number(d, (char_u *)"end_col");
vcol = (int)dict_get_number(d, (char_u *)"vcol");
nr = (int)dict_get_number(d, (char_u *)"nr");
type = dict_get_string(d, (char_u *)"type", TRUE);
@@ -7180,7 +7234,9 @@ qf_add_entry_from_dict(
bufnum,
text,
lnum,
end_lnum,
col,
end_col,
vcol, // vis_col
pattern, // search pattern
nr,
@@ -8048,8 +8104,11 @@ hgr_search_file(
0,
line,
lnum,
0,
(int)(p_regmatch->startp[0] - line)
+ 1, // col
(int)(p_regmatch->endp[0] - line)
+ 1, // end_col
FALSE, // vis_col
NULL, // search pattern
0, // nr
+3
View File
@@ -462,6 +462,9 @@ stuff_yank(int regname, char_u *p)
return OK;
}
/*
* Last executed register (@ command)
*/
static int execreg_lastc = NUL;
int
+8 -2
View File
@@ -1629,6 +1629,11 @@ typedef struct
# endif
garray_T uf_lines; // function lines
int uf_debug_tick; // when last checked for a breakpoint in this
// function.
int uf_has_breakpoint; // TRUE when a breakpoint has been set in
// this function.
# ifdef FEAT_PROFILE
int uf_profiling; // TRUE when func is being profiled
int uf_prof_initialized;
@@ -2516,11 +2521,12 @@ typedef struct {
# define CRYPT_M_ZIP 0
# define CRYPT_M_BF 1
# define CRYPT_M_BF2 2
# define CRYPT_M_COUNT 3 // number of crypt methods
# define CRYPT_M_SOD 3
# define CRYPT_M_COUNT 4 // number of crypt methods
// Currently all crypt methods work inplace. If one is added that isn't then
// define this.
// # define CRYPT_NOT_INPLACE 1
# define CRYPT_NOT_INPLACE 1
#endif
#ifdef FEAT_PROP_POPUP
@@ -4,9 +4,9 @@
|m|a|t|c|h|e|s| @67
|~+0#4040ff13&| @73
|X+1#0000000&|C|w|i|n|d|o|w| @48|1|,|4| @11|A|l@1
>X+0#0000e05#ffff4012|C|w|i|n|d|o|w||+0#0000000&|1+0#af5f00255&| |c|o|l| |4||+0#0000000&| |s|o|m|e| @52
|X+0#0000e05#ffffff0|C|w|i|n|d|o|w||+0#0000000&|2+0#af5f00255&| |c|o|l| |2||+0#0000000&| |t|e|x|t| @52
|X+0#0000e05&|C|w|i|n|d|o|w||+0#0000000&|4+0#af5f00255&| |c|o|l| |6||+0#0000000&| |m|a|t|c|h|e|s| @49
>X+0#0000e05#ffff4012|C|w|i|n|d|o|w||+0#0000000&|1+0#af5f00255&| |c|o|l| |4|-|5||+0#0000000&| |s|o|m|e| @50
|X+0#0000e05#ffffff0|C|w|i|n|d|o|w||+0#0000000&|2+0#af5f00255&| |c|o|l| |2|-|3||+0#0000000&| |t|e|x|t| @50
|X+0#0000e05&|C|w|i|n|d|o|w||+0#0000000&|4+0#af5f00255&| |c|o|l| |6|-|7||+0#0000000&| |m|a|t|c|h|e|s| @47
|~+0#4040ff13&| @73
|[+3#0000000&|Q|u|i|c|k|f|i|x| |L|i|s|t|]| |:|v|i|m|g|r|e|p| |e| |X|C|w|i|n|d|o|w| @20|1|,|1| @12|A|l@1
| +0&&@74
@@ -4,9 +4,9 @@
|m|a|t|c|h|e|s| @67
|~+0#4040ff13&| @73
|X+3#0000000&|C|w|i|n|d|o|w| @48|2|,|2| @11|A|l@1
|X+0#0000e05&|C|w|i|n|d|o|w||+0#0000000&|1+0#af5f00255&| |c|o|l| |4||+0#0000000&| |s|o|m|e| @52
|X+0#0000e05#ffff4012|C|w|i|n|d|o|w||+0#0000000&|2+0#af5f00255&| |c|o|l| |2||+0#0000000&| |t|e|x|t| @52
|X+0#0000e05#ffffff0|C|w|i|n|d|o|w||+0#0000000&|4+0#af5f00255&| |c|o|l| |6||+0#0000000&| |m|a|t|c|h|e|s| @49
|X+0#0000e05&|C|w|i|n|d|o|w||+0#0000000&|1+0#af5f00255&| |c|o|l| |4|-|5||+0#0000000&| |s|o|m|e| @50
|X+0#0000e05#ffff4012|C|w|i|n|d|o|w||+0#0000000&|2+0#af5f00255&| |c|o|l| |2|-|3||+0#0000000&| |t|e|x|t| @50
|X+0#0000e05#ffffff0|C|w|i|n|d|o|w||+0#0000000&|4+0#af5f00255&| |c|o|l| |6|-|7||+0#0000000&| |m|a|t|c|h|e|s| @47
|~+0#4040ff13&| @73
|[+1#0000000&|Q|u|i|c|k|f|i|x| |L|i|s|t|]| |:|v|i|m|g|r|e|p| |e| |X|C|w|i|n|d|o|w| @20|2|,|1| @12|A|l@1
|:+0&&|c|n|e|x|t| @68
Binary file not shown.
+2
View File
@@ -374,6 +374,8 @@ func Test_mouse_position()
call test_setmouse(5, 1)
call feedkeys("\<LeftMouse>", "xt")
call assert_equal([0, 2, 1, 0], getpos('.'))
call assert_fails('call test_setmouse("", 2)', 'E474:')
call assert_fails('call test_setmouse(1, "")', 'E474:')
bwipe!
let &mouse = save_mouse
endfunc
+126 -1
View File
@@ -22,6 +22,11 @@ func Test_head_only_3()
call Common_head_only('VimCrypt~03!abc')
endfunc
func Test_head_only_4()
CheckFeature sodium
call Common_head_only('VimCrypt~04!abc')
endfunc
func Crypt_uncrypt(method)
exe "set cryptmethod=" . a:method
" If the blowfish test fails 'cryptmethod' will be 'zip' now.
@@ -55,6 +60,11 @@ func Test_crypt_blowfish2()
call Crypt_uncrypt('blowfish2')
endfunc
func Test_crypt_sodium()
CheckFeature sodium
call Crypt_uncrypt('xchacha20')
endfunc
func Uncrypt_stable(method, crypted_text, key, uncrypted_text)
split Xtest.txt
set bin noeol key= fenc=latin1
@@ -70,6 +80,16 @@ func Uncrypt_stable(method, crypted_text, key, uncrypted_text)
set key=
endfunc
func Uncrypt_stable_xxd(method, hex, key, uncrypted_text)
" use xxd to write the binary content
call system('xxd -r >Xtest.txt', a:hex)
call feedkeys(":split Xtest.txt\<CR>" . a:key . "\<CR>", 'xt')
call assert_equal(a:uncrypted_text, getline(1, len(a:uncrypted_text)))
bwipe!
call delete('Xtest.txt')
set key=
endfunc
func Test_uncrypt_zip()
call Uncrypt_stable('zip', "VimCrypt~01!\u0006\u001clV'\u00de}Mg\u00a0\u00ea\u00a3V\u00a9\u00e7\u0007E#3\u008e2U\u00e9\u0097", "foofoo", ["1234567890", "aábbccddeëff"])
endfunc
@@ -78,10 +98,115 @@ func Test_uncrypt_blowfish()
call Uncrypt_stable('blowfish', "VimCrypt~02!k)\u00be\u0017\u0097#\u0016\u00ddS\u009c\u00f5=\u00ba\u00e0\u00c8#\u00a5M\u00b4\u0086J\u00c3A\u00cd\u00a5M\u00b4\u0086!\u0080\u0015\u009b\u00f5\u000f\u00e1\u00d2\u0019\u0082\u0016\u0098\u00f7\u000d\u00da", "barbar", ["asdfasdfasdf", "0001112223333"])
endfunc
func Test_uncrypt_blowfish2()
func Test_uncrypt_blowfish2a()
call Uncrypt_stable('blowfish', "VimCrypt~03!\u001e\u00d1N\u00e3;\u00d3\u00c0\u00a0^C)\u0004\u00f7\u007f.\u00b6\u00abF\u000eS\u0019\u00e0\u008b6\u00d2[T\u00cb\u00a7\u0085\u00d8\u00be9\u000b\u00812\u000bQ\u00b3\u00cc@\u0097\u000f\u00df\u009a\u00adIv\u00aa.\u00d8\u00c9\u00ee\u009e`\u00bd$\u00af%\u00d0", "barburp", ["abcdefghijklmnopqrstuvwxyz", "!@#$%^&*()_+=-`~"])
endfunc
func Test_uncrypt_blowfish2()
call Uncrypt_stable('blowfish2', "VimCrypt~03!\u001e\u00d1N\u00e3;\u00d3\u00c0\u00a0^C)\u0004\u00f7\u007f.\u00b6\u00abF\u000eS\u0019\u00e0\u008b6\u00d2[T\u00cb\u00a7\u0085\u00d8\u00be9\u000b\u00812\u000bQ\u00b3\u00cc@\u0097\u000f\u00df\u009a\u00adIv\u00aa.\u00d8\u00c9\u00ee\u009e`\u00bd$\u00af%\u00d0", "barburp", ["abcdefghijklmnopqrstuvwxyz", "!@#$%^&*()_+=-`~"])
endfunc
func Test_uncrypt_xchacha20()
CheckFeature sodium
let hex=['00000000: 5669 6d43 7279 7074 7e30 3421 6b7d e607 vimCrypt~04!k}..',
\ '00000010: 4ea4 e99f 923e f67f 7b59 a80d 3bca 2f06 N....>..{Y..;./.',
\ '00000020: fa11 b951 8d09 0dc9 470f e7cf 8b90 4310 ...Q....G.....C.',
\ '00000030: 653b b83b e493 378b 0390 0e38 f912 626b e;.;..7....8..bk',
\ '00000040: a02e 4697 0254 2625 2d8e 3a0b 784b e89c ..F..T&%-.:.xK..',
\ '00000050: 0c67 a975 3c17 9319 8ffd 1463 7783 a1f3 .g.u<......cw...',
\ '00000060: d917 dcb3 8b3e ecd7 c7d4 086b 6059 7ead .....>.....k`Y~.',
\ '00000070: 9b07 f96b 5c1b 4d08 cd91 f208 5221 7484 ...k\.M.....R!t.',
\ '00000080: 72be 0136 84a1 d3 r..6...']
" the file should be in latin1 encoding, this makes sure that readfile()
" retries several times converting the multi-byte characters
call Uncrypt_stable_xxd('xchacha20', hex, "sodium_crypt", ["abcdefghijklmnopqrstuvwxyzäöü", "ZZZ_äüöÄÜÖ_!@#$%^&*()_+=-`~"])
endfunc
func Test_uncrypt_xchacha20_invalid()
CheckFeature sodium
" load an invalid encrypted file and verify it can be decrypted with an
" error message
try
call feedkeys(":split samples/crypt_sodium_invalid.txt\<CR>sodium\<CR>", 'xt')
call assert_false(1, 'should not happen')
catch
call assert_exception('pre-mature')
endtry
call assert_match("Note: Encryption of swapfile not supported, disabling swap- and undofile", execute(':5messages'))
call assert_equal(0, &swapfile)
call assert_equal("xchacha20", &cryptmethod)
call assert_equal('311111111111111111111111', getline('$'))
bw!
endfunc
func Test_uncrypt_xchacha20_2()
CheckFeature sodium
sp Xcrypt_sodium.txt
" Create a larger file, so that Vim will write in several blocks
call setline(1, range(1,4000))
call assert_equal(1, &swapfile)
set cryptmethod=xchacha20
call feedkeys(":X\<CR>sodium\<CR>sodium\<CR>", 'xt')
" swapfile disabled
call assert_equal(0, &swapfile)
call assert_match("Note: Encryption of swapfile not supported, disabling swap- and undofile", execute(':messages'))
w!
" encrypted using xchacha20
call assert_match("\[xchacha20\]", execute(':messages'))
bw!
call feedkeys(":sp Xcrypt_sodium.txt\<CR>sodium\<CR>", 'xt')
" successfully decrypted
call assert_equal(range(1, 4000)->map( {_, v -> string(v)}), getline(1,'$'))
set key=
w!
" enryption removed
call assert_match('"Xcrypt_sodium.txt" 4000L, 18893B written', execute(':message'))
bw!
call delete('Xcrypt_sodium.txt')
set cryptmethod&vim
endfunc
func Test_uncrypt_xchacha20_3_persistent_undo()
CheckFeature sodium
CheckFeature persistent_undo
sp Xcrypt_sodium_undo.txt
set cryptmethod=xchacha20 undofile
call feedkeys(":X\<CR>sodium\<CR>sodium\<CR>", 'xt')
call assert_equal(0, &undofile)
let ufile=undofile(@%)
call append(0, ['monday', 'tuesday', 'wednesday', 'thursday', 'friday'])
call cursor(1, 1)
set undolevels=100
normal dd
set undolevels=100
normal dd
set undolevels=100
normal dd
set undolevels=100
w!
bw!
call feedkeys(":sp Xcrypt_sodium_undo.txt\<CR>sodium\<CR>", 'xt')
" should fail
norm! u
call assert_match('Already at oldest change', execute(':1mess'))
call assert_fails('verbose rundo' .. fnameescape(ufile), 'E822')
bw!
set undolevels& cryptmethod& undofile&
call delete('Xcrypt_sodium_undo.txt')
endfunc
func Test_encrypt_xchacha20_missing()
if has("sodium")
return
endif
sp Xcrypt_sodium_undo.txt
call assert_fails(':set cryptmethod=xchacha20', 'E474')
bw!
set cm&
endfunc
func Test_uncrypt_unknown_method()
split Xuncrypt_unknown.txt
set bin noeol key= fenc=latin1
+107 -11
View File
@@ -885,19 +885,19 @@ func Test_Backtrace_DefFunction()
\ ':debug call GlobalFunction()',
\ ['cmd: call GlobalFunction()'])
call RunDbgCmd(buf, 'step', ['line 1: var some = "some var"'])
call RunDbgCmd(buf, 'step', ['line 2: CallAFunction()'])
call RunDbgCmd(buf, 'step', ['line 1: var some = "some var"'])
call RunDbgCmd(buf, 'step', ['line 2: CallAFunction()'])
call RunDbgCmd(buf, 'echo some', ['some var'])
call RunDbgCmd(buf, 'backtrace', [
\ '\V>backtrace',
\ '\V->0 function GlobalFunction',
\ '\Vline 2: CallAFunction()',
\ '\Vline 2: CallAFunction()',
\ ],
\ #{match: 'pattern'})
call RunDbgCmd(buf, 'step', ['line 1: SourceAnotherFile()'])
call RunDbgCmd(buf, 'step', ['line 1: source Xtest2.vim'])
call RunDbgCmd(buf, 'step', ['line 1: SourceAnotherFile()'])
call RunDbgCmd(buf, 'step', ['line 1: source Xtest2.vim'])
" Repeated line, because we fist are in the compiled function before the
" EXEC and then in do_cmdline() before the :source command.
call RunDbgCmd(buf, 'step', ['line 1: source Xtest2.vim'])
@@ -932,17 +932,83 @@ func Test_Backtrace_DefFunction()
call delete('Xtest2.vim')
endfunc
func Test_debug_DefFunction()
CheckCWD
let file =<< trim END
vim9script
def g:SomeFunc()
echo "here"
echo "and"
echo "there"
breakadd func 2 LocalFunc
LocalFunc()
enddef
def LocalFunc()
echo "first"
echo "second"
breakadd func 1 LegacyFunc
LegacyFunc()
enddef
func LegacyFunc()
echo "legone"
echo "legtwo"
endfunc
breakadd func 2 g:SomeFunc
END
call writefile(file, 'XtestDebug.vim')
let buf = RunVimInTerminal('-S XtestDebug.vim', {})
call RunDbgCmd(buf,':call SomeFunc()', ['line 2: echo "and"'])
call RunDbgCmd(buf,'next', ['line 3: echo "there"'])
call RunDbgCmd(buf,'next', ['line 4: breakadd func 2 LocalFunc'])
" continue, next breakpoint is in LocalFunc()
call RunDbgCmd(buf,'cont', ['line 2: echo "second"'])
" continue, next breakpoint is in LegacyFunc()
call RunDbgCmd(buf,'cont', ['line 1: echo "legone"'])
call RunDbgCmd(buf, 'cont')
call StopVimInTerminal(buf)
call delete('Xtest1.vim')
call delete('Xtest2.vim')
endfunc
func Test_debug_def_function()
CheckCWD
let file =<< trim END
vim9script
def g:Func()
var n: number
def Closure(): number
return n + 3
enddef
n += Closure()
echo 'result: ' .. n
var n: number
def Closure(): number
return n + 3
enddef
n += Closure()
echo 'result: ' .. n
enddef
def g:FuncWithArgs(text: string, nr: number, ...items: list<number>)
echo text .. nr
for it in items
echo it
endfor
echo "done"
enddef
def g:FuncWithDict()
var d = {
a: 1,
b: 2,
}
# comment
def Inner()
eval 1
enddef
enddef
END
call writefile(file, 'Xtest.vim')
@@ -954,7 +1020,37 @@ func Test_debug_def_function()
\ ['cmd: call Func()'])
call RunDbgCmd(buf, 'next', ['result: 3'])
call term_sendkeys(buf, "\r")
call RunDbgCmd(buf, 'cont')
call RunDbgCmd(buf,
\ ':debug call FuncWithArgs("asdf", 42, 1, 2, 3)',
\ ['cmd: call FuncWithArgs("asdf", 42, 1, 2, 3)'])
call RunDbgCmd(buf, 'step', ['line 1: echo text .. nr'])
call RunDbgCmd(buf, 'echo text', ['asdf'])
call RunDbgCmd(buf, 'echo nr', ['42'])
call RunDbgCmd(buf, 'echo items', ['[1, 2, 3]'])
call RunDbgCmd(buf, 'step', ['asdf42', 'function FuncWithArgs', 'line 2: for it in items'])
call RunDbgCmd(buf, 'echo it', ['1'])
call RunDbgCmd(buf, 'step', ['line 3: echo it'])
call RunDbgCmd(buf, 'step', ['1', 'function FuncWithArgs', 'line 4: endfor'])
call RunDbgCmd(buf, 'step', ['line 2: for it in items'])
call RunDbgCmd(buf, 'echo it', ['2'])
call RunDbgCmd(buf, 'step', ['line 3: echo it'])
call RunDbgCmd(buf, 'step', ['2', 'function FuncWithArgs', 'line 4: endfor'])
call RunDbgCmd(buf, 'step', ['line 2: for it in items'])
call RunDbgCmd(buf, 'echo it', ['3'])
call RunDbgCmd(buf, 'step', ['line 3: echo it'])
call RunDbgCmd(buf, 'step', ['3', 'function FuncWithArgs', 'line 4: endfor'])
call RunDbgCmd(buf, 'step', ['line 5: echo "done"'])
call RunDbgCmd(buf, 'cont')
call RunDbgCmd(buf,
\ ':debug call FuncWithDict()',
\ ['cmd: call FuncWithDict()'])
call RunDbgCmd(buf, 'step', ['line 1: var d = { a: 1, b: 2, }'])
call RunDbgCmd(buf, 'step', ['line 6: def Inner()'])
call RunDbgCmd(buf, 'cont')
call StopVimInTerminal(buf)
call delete('Xtest.vim')
endfunc
+1 -1
View File
@@ -165,7 +165,7 @@ func Test_string_concat_scriptversion2()
call assert_fails('echo a . b', 'E15:')
call assert_fails('let a .= b', 'E985:')
call assert_fails('let vers = 1.2.3', 'E15:')
call assert_fails('let vers = 1.2.3', 'E488:')
if has('float')
let f = .5
+1 -1
View File
@@ -40,7 +40,7 @@ func Test_execute_string()
if has('float')
call assert_fails('call execute(3.4)', 'E492:')
call assert_equal("\nx", execute("echo \"x\"", 3.4))
call CheckDefExecAndScriptFailure(['execute("echo \"x\"", 3.4)'], 'E806:')
call CheckDefExecAndScriptFailure2(['execute("echo \"x\"", 3.4)'], 'E1013: Argument 2: type mismatch, expected string but got float', 'E806:')
endif
endfunc
+16
View File
@@ -1,5 +1,7 @@
" Test for 'fileformat'
source shared.vim
" Test behavior of fileformat after bwipeout of last buffer
func Test_fileformat_after_bw()
bwipeout
@@ -308,4 +310,18 @@ func Test_fileformat_plusplus_read()
call assert_fails('e ++abc1 Xfile1', 'E474:')
endfunc
" When Vim starts up with an empty buffer the first item in 'fileformats' is
" used as the 'fileformat'.
func Test_fileformat_on_startup()
let after =<< trim END
call writefile([&fileformat], 'Xfile', 'a')
quit
END
call RunVim(["set ffs=dos,unix,mac"], after, '')
call RunVim(["set ffs=mac,dos,unix"], after, '')
call RunVim(["set ffs=unix,mac,dos"], after, '')
call assert_equal(['dos', 'mac', 'unix'], readfile('Xfile'))
call delete('Xfile')
endfunc
" vim: shiftwidth=2 sts=2 expandtab
+4
View File
@@ -83,4 +83,8 @@ func Test_global_newline()
close!
endfunc
func Test_wrong_delimiter()
call assert_fails('g x^bxd', 'E146:')
endfunc
" vim: shiftwidth=2 sts=2 expandtab
+284 -1
View File
@@ -389,7 +389,7 @@ func Test_set_guifont()
endif
" This only works if 'renderoptions' exists and does not work for Windows XP
" and older.
" and older.
if exists('+renderoptions') && windowsversion() !~ '^[345]\.'
" doing this four times used to cause a crash
set renderoptions=type:directx
@@ -880,4 +880,287 @@ func Test_gui_recursive_mapping()
nunmap <C-W>a
endfunc
" Test GUI mouse events
func Test_gui_mouse_event()
set mousemodel=extend
call test_override('no_query_mouse', 1)
new
call setline(1, ['one two three', 'four five six'])
" place the cursor using left click in normal mode
call cursor(1, 1)
call test_gui_mouse_event(0, 2, 4, 0, 0)
call test_gui_mouse_event(3, 2, 4, 0, 0)
call feedkeys("\<Esc>", 'Lx!')
call assert_equal([0, 2, 4, 0], getpos('.'))
" select and yank a word
let @" = ''
call test_gui_mouse_event(0, 1, 9, 0, 0)
call test_gui_mouse_event(0, 1, 9, 1, 0)
call test_gui_mouse_event(3, 1, 9, 0, 0)
call feedkeys("y", 'Lx!')
call assert_equal('three', @")
" create visual selection using right click
let @" = ''
call test_gui_mouse_event(0, 2, 6, 0, 0)
call test_gui_mouse_event(3, 2, 6, 0, 0)
call test_gui_mouse_event(2, 2, 13, 0, 0)
call test_gui_mouse_event(3, 2, 13, 0, 0)
call feedkeys("y", 'Lx!')
call assert_equal('five six', @")
" paste using middle mouse button
let @* = 'abc '
call feedkeys('""', 'Lx!')
call test_gui_mouse_event(1, 1, 9, 0, 0)
call test_gui_mouse_event(3, 1, 9, 0, 0)
call feedkeys("\<Esc>", 'Lx!')
call assert_equal(['one two abc three', 'four five six'], getline(1, '$'))
" extend visual selection using right click in visual mode
let @" = ''
call cursor(1, 1)
call feedkeys('v', 'Lx!')
call test_gui_mouse_event(2, 1, 17, 0, 0)
call test_gui_mouse_event(3, 1, 17, 0, 0)
call feedkeys("y", 'Lx!')
call assert_equal('one two abc three', @")
" extend visual selection using mouse drag
let @" = ''
call cursor(1, 1)
call test_gui_mouse_event(0, 2, 1, 0, 0)
call test_gui_mouse_event(0x43, 2, 9, 0, 0)
call test_gui_mouse_event(0x3, 2, 9, 0, 0)
call feedkeys("y", 'Lx!')
call assert_equal('four five', @")
" select text by moving the mouse
let @" = ''
call cursor(1, 1)
redraw!
call test_gui_mouse_event(0, 1, 4, 0, 0)
call test_gui_mouse_event(0x700, 1, 9, 0, 0)
call test_gui_mouse_event(0x700, 1, 13, 0, 0)
call test_gui_mouse_event(0x3, 1, 13, 0, 0)
call feedkeys("y", 'Lx!')
call assert_equal(' two abc t', @")
" Using mouse in insert mode
call cursor(1, 1)
call feedkeys('i', 't')
call test_gui_mouse_event(0, 2, 11, 0, 0)
call test_gui_mouse_event(3, 2, 11, 0, 0)
call feedkeys("po\<Esc>", 'Lx!')
call assert_equal(['one two abc three', 'four five posix'], getline(1, '$'))
%d _
call setline(1, range(1, 100))
" scroll up
call test_gui_mouse_event(0x200, 2, 1, 0, 0)
call test_gui_mouse_event(0x200, 2, 1, 0, 0)
call test_gui_mouse_event(0x200, 2, 1, 0, 0)
call feedkeys("H", 'Lx!')
call assert_equal(10, line('.'))
" scroll down
call test_gui_mouse_event(0x100, 2, 1, 0, 0)
call test_gui_mouse_event(0x100, 2, 1, 0, 0)
call feedkeys("H", 'Lx!')
call assert_equal(4, line('.'))
%d _
set nowrap
call setline(1, range(10)->join('')->repeat(10))
" scroll left
call test_gui_mouse_event(0x500, 1, 5, 0, 0)
call test_gui_mouse_event(0x500, 1, 10, 0, 0)
call test_gui_mouse_event(0x500, 1, 15, 0, 0)
call feedkeys('g0', 'Lx!')
call assert_equal(19, col('.'))
" scroll right
call test_gui_mouse_event(0x600, 1, 15, 0, 0)
call test_gui_mouse_event(0x600, 1, 10, 0, 0)
call feedkeys('g0', 'Lx!')
call assert_equal(7, col('.'))
set wrap&
%d _
call setline(1, repeat([repeat('a', 60)], 10))
" record various mouse events
let mouseEventNames = [
\ 'LeftMouse', 'LeftRelease', '2-LeftMouse', '3-LeftMouse',
\ 'S-LeftMouse', 'A-LeftMouse', 'C-LeftMouse', 'MiddleMouse',
\ 'MiddleRelease', '2-MiddleMouse', '3-MiddleMouse',
\ 'S-MiddleMouse', 'A-MiddleMouse', 'C-MiddleMouse',
\ 'RightMouse', 'RightRelease', '2-RightMouse',
\ '3-RightMouse', 'S-RightMouse', 'A-RightMouse', 'C-RightMouse',
\ 'X1Mouse', 'S-X1Mouse', 'A-X1Mouse', 'C-X1Mouse', 'X2Mouse',
\ 'S-X2Mouse', 'A-X2Mouse', 'C-X2Mouse'
\ ]
let mouseEventCodes = map(copy(mouseEventNames), "'<' .. v:val .. '>'")
let g:events = []
for e in mouseEventCodes
exe 'nnoremap ' .. e .. ' <Cmd>call add(g:events, "' ..
\ substitute(e, '[<>]', '', 'g') .. '")<CR>'
endfor
" Test various mouse buttons (0 - Left, 1 - Middle, 2 - Right, 0x300 - X1,
" 0x300- X2)
for button in [0, 1, 2, 0x300, 0x400]
" Single click
call test_gui_mouse_event(button, 2, 5, 0, 0)
call test_gui_mouse_event(3, 2, 5, 0, 0)
" Double/Triple click is supported by only the Left/Middle/Right mouse
" buttons
if button <= 2
" Double Click
call test_gui_mouse_event(button, 2, 5, 0, 0)
call test_gui_mouse_event(button, 2, 5, 1, 0)
call test_gui_mouse_event(3, 2, 5, 0, 0)
" Triple Click
call test_gui_mouse_event(button, 2, 5, 0, 0)
call test_gui_mouse_event(button, 2, 5, 1, 0)
call test_gui_mouse_event(button, 2, 5, 1, 0)
call test_gui_mouse_event(3, 2, 5, 0, 0)
endif
" Shift click
call test_gui_mouse_event(button, 3, 7, 0, 4)
call test_gui_mouse_event(3, 3, 7, 0, 4)
" Alt click
call test_gui_mouse_event(button, 3, 7, 0, 8)
call test_gui_mouse_event(3, 3, 7, 0, 8)
" Ctrl click
call test_gui_mouse_event(button, 3, 7, 0, 16)
call test_gui_mouse_event(3, 3, 7, 0, 16)
call feedkeys("\<Esc>", 'Lx!')
endfor
call assert_equal(['LeftMouse', 'LeftRelease', 'LeftMouse', '2-LeftMouse',
\ 'LeftMouse', '2-LeftMouse', '3-LeftMouse', 'S-LeftMouse',
\ 'A-LeftMouse', 'C-LeftMouse', 'MiddleMouse', 'MiddleRelease',
\ 'MiddleMouse', '2-MiddleMouse', 'MiddleMouse', '2-MiddleMouse',
\ '3-MiddleMouse', 'S-MiddleMouse', 'A-MiddleMouse', 'C-MiddleMouse',
\ 'RightMouse', 'RightRelease', 'RightMouse', '2-RightMouse',
\ 'RightMouse', '2-RightMouse', '3-RightMouse', 'S-RightMouse',
\ 'A-RightMouse', 'C-RightMouse', 'X1Mouse', 'S-X1Mouse', 'A-X1Mouse',
\ 'C-X1Mouse', 'X2Mouse', 'S-X2Mouse', 'A-X2Mouse', 'C-X2Mouse'],
\ g:events)
for e in mouseEventCodes
exe 'nunmap ' .. e
endfor
" modeless selection
set mouse=
let save_guioptions = &guioptions
set guioptions+=A
%d _
call setline(1, ['one two three', 'four five sixteen'])
call cursor(1, 1)
redraw!
" Double click should select the word and copy it to clipboard
let @* = ''
call test_gui_mouse_event(0, 2, 11, 0, 0)
call test_gui_mouse_event(0, 2, 11, 1, 0)
call test_gui_mouse_event(3, 2, 11, 0, 0)
call feedkeys("\<Esc>", 'Lx!')
call assert_equal([0, 1, 1, 0], getpos('.'))
call assert_equal('sixteen', @*)
" Right click should extend the selection from cursor
call cursor(1, 6)
redraw!
let @* = ''
call test_gui_mouse_event(2, 1, 11, 0, 0)
call test_gui_mouse_event(3, 1, 11, 0, 0)
call feedkeys("\<Esc>", 'Lx!')
call assert_equal([0, 1, 6, 0], getpos('.'))
call assert_equal('wo thr', @*)
" Middle click should paste the clipboard contents
call cursor(2, 1)
redraw!
call test_gui_mouse_event(1, 1, 11, 0, 0)
call test_gui_mouse_event(3, 1, 11, 0, 0)
call feedkeys("\<Esc>", 'Lx!')
call assert_equal([0, 2, 7, 0], getpos('.'))
call assert_equal('wo thrfour five sixteen', getline(2))
set mouse&
let &guioptions = save_guioptions
" Test invalid parameters for test_gui_mouse_event()
call assert_fails('call test_gui_mouse_event("", 1, 2, 3, 4)', 'E474:')
call assert_fails('call test_gui_mouse_event(0, "", 2, 3, 4)', 'E474:')
call assert_fails('call test_gui_mouse_event(0, 1, "", 3, 4)', 'E474:')
call assert_fails('call test_gui_mouse_event(0, 1, 2, "", 4)', 'E474:')
call assert_fails('call test_gui_mouse_event(0, 1, 2, 3, "")', 'E474:')
bw!
call test_override('no_query_mouse', 0)
set mousemodel&
endfunc
" Test for 'guitablabel' and 'guitabtooltip' options
func TestGuiTabLabel()
call add(g:TabLabels, v:lnum + 100)
let bufnrlist = tabpagebuflist(v:lnum)
return bufname(bufnrlist[tabpagewinnr(v:lnum) - 1])
endfunc
func TestGuiTabToolTip()
call add(g:TabToolTips, v:lnum + 200)
let bufnrlist = tabpagebuflist(v:lnum)
return bufname(bufnrlist[tabpagewinnr(v:lnum) - 1])
endfunc
func Test_gui_tablabel_tooltip()
%bw!
" Removing the tabline at the end of this test, reduces the window height by
" one. Save and restore it after the test.
let save_lines = &lines
edit one
set modified
tabnew two
set modified
tabnew three
set modified
let g:TabLabels = []
set guitablabel=%{TestGuiTabLabel()}
call test_override('starting', 1)
redrawtabline
call test_override('starting', 0)
call assert_true(index(g:TabLabels, 101) != -1)
call assert_true(index(g:TabLabels, 102) != -1)
call assert_true(index(g:TabLabels, 103) != -1)
set guitablabel&
unlet g:TabLabels
if has('gui_gtk')
" Only on GTK+, the tooltip function is called even if the mouse is not
" on the tabline. on Win32 and Motif, the tooltip function is called only
" when the mouse pointer is over the tabline.
let g:TabToolTips = []
set guitabtooltip=%{TestGuiTabToolTip()}
call test_override('starting', 1)
redrawtabline
call test_override('starting', 0)
call assert_true(index(g:TabToolTips, 201) != -1)
call assert_true(index(g:TabToolTips, 202) != -1)
call assert_true(index(g:TabToolTips, 203) != -1)
set guitabtooltip&
unlet g:TabToolTips
endif
%bw!
let &lines = save_lines
endfunc
" vim: shiftwidth=2 sts=2 expandtab
+1
View File
@@ -314,6 +314,7 @@ func Test_let_errors()
let ch = test_null_channel()
call assert_fails('let ch += 1', 'E734:')
endif
call assert_fails('let name = "a" .. "b",', 'E488: Trailing characters: ,')
" This test works only when the language is English
if v:lang == "C" || v:lang =~ '^[Ee]n'
+22
View File
@@ -298,4 +298,26 @@ func Test_relativenumber_colors()
call delete('XTest_relnr')
endfunc
" Test for displaying line numbers with 'rightleft'
func Test_number_rightleft()
CheckFeature rightleft
new
setlocal number
setlocal rightleft
call setline(1, range(1, 1000))
normal! 9Gzt
redraw!
call assert_match('^\s\+9 9$', Screenline(1))
normal! 10Gzt
redraw!
call assert_match('^\s\+01 10$', Screenline(1))
normal! 100Gzt
redraw!
call assert_match('^\s\+001 100$', Screenline(1))
normal! 1000Gzt
redraw!
call assert_match('^\s\+0001 1000$', Screenline(1))
bw!
endfunc
" vim: shiftwidth=2 sts=2 expandtab
+2 -2
View File
@@ -1552,8 +1552,8 @@ func Test_popup_filter()
call assert_equal(9, getcurpos()[2])
call feedkeys('0', 'xt')
call assert_equal('0', g:ignored)
redraw
call assert_equal(1, getcurpos()[2])
normal! l
call assert_equal(2, getcurpos()[2])
" x closes the popup
call feedkeys('x', 'xt')
+125 -5
View File
@@ -134,6 +134,21 @@ func XlistTests(cchar)
call assert_equal([' 2 Xtestfile1:1 col 3: Line1',
\ ' 3: non-error 2', ' 4 Xtestfile2:2 col 2: Line2'], l)
" Ranged entries
call g:Xsetlist([{'lnum':10,'text':'Line1'},
\ {'lnum':20,'col':10,'text':'Line2'},
\ {'lnum':30,'col':15,'end_col':20,'text':'Line3'},
\ {'lnum':40,'end_lnum':45,'text':'Line4'},
\ {'lnum':50,'end_lnum':55,'col':15,'text':'Line5'},
\ {'lnum':60,'end_lnum':65,'col':25,'end_col':35,'text':'Line6'}])
let l = split(execute('Xlist', ""), "\n")
call assert_equal([' 1:10: Line1',
\ ' 2:20 col 10: Line2',
\ ' 3:30 col 15-20: Line3',
\ ' 4:40-45: Line4',
\ ' 5:50-55 col 15: Line5',
\ ' 6:60-65 col 25-35: Line6'], l)
" Different types of errors
call g:Xsetlist([{'lnum':10,'col':5,'type':'W', 'text':'Warning','nr':11},
\ {'lnum':20,'col':10,'type':'e','text':'Error','nr':22},
@@ -644,6 +659,7 @@ func s:test_xhelpgrep(cchar)
call assert_true(&buftype == 'help')
call assert_true(winnr() == 1)
call assert_true(winnr('$') == 2)
call assert_match('|\d\+ col \d\+-\d\+|', getbufline(winbufnr(2), 1)[0])
" This wipes out the buffer, make sure that doesn't cause trouble.
Xclose
@@ -1514,10 +1530,13 @@ func SetXlistTests(cchar, bnum)
call s:setup_commands(a:cchar)
call g:Xsetlist([{'bufnr': a:bnum, 'lnum': 1},
\ {'bufnr': a:bnum, 'lnum': 2}])
\ {'bufnr': a:bnum, 'lnum': 2, 'end_lnum': 3, 'col': 4, 'end_col': 5}])
let l = g:Xgetlist()
call assert_equal(2, len(l))
call assert_equal(2, l[1].lnum)
call assert_equal(3, l[1].end_lnum)
call assert_equal(4, l[1].col)
call assert_equal(5, l[1].end_col)
Xnext
call g:Xsetlist([{'bufnr': a:bnum, 'lnum': 3}], 'a')
@@ -2852,7 +2871,9 @@ func XvimgrepTests(cchar)
let l = g:Xgetlist()
call assert_equal(2, len(l))
call assert_equal(8, l[0].col)
call assert_equal(11, l[0].end_col)
call assert_equal(12, l[1].col)
call assert_equal(15, l[1].end_col)
1Xvimgrep ?Editor? Xtestfile*
let l = g:Xgetlist()
@@ -5098,15 +5119,21 @@ func Xtest_qftextfunc(cchar)
call assert_equal('Tqfexpr', &quickfixtextfunc)
call assert_equal('',
\ g:Xgetlist({'quickfixtextfunc' : 1}).quickfixtextfunc)
Xexpr ['F1:10:2:green', 'F1:20:4:blue']
call g:Xsetlist([
\ { 'filename': 'F1', 'lnum': 10, 'col': 2,
\ 'end_col': 7, 'text': 'green'},
\ { 'filename': 'F1', 'lnum': 20, 'end_lnum': 25, 'col': 4,
\ 'end_col': 8, 'text': 'blue'},
\ ])
Xwindow
call assert_equal('F1-L10C2-green', getline(1))
call assert_equal('F1-L20C4-blue', getline(2))
Xclose
set quickfixtextfunc&vim
Xwindow
call assert_equal('F1|10 col 2| green', getline(1))
call assert_equal('F1|20 col 4| blue', getline(2))
call assert_equal('F1|10 col 2-7| green', getline(1))
call assert_equal('F1|20-25 col 4-8| blue', getline(2))
Xclose
set efm&
set quickfixtextfunc&
@@ -5231,6 +5258,64 @@ func Test_qftextfunc()
call Xtest_qftextfunc('l')
endfunc
" Test for updating a location list for some other window and check that
" 'qftextfunc' uses the correct location list.
func Test_qftextfunc_other_loclist()
%bw!
call setloclist(0, [], 'f')
" create a window and a location list for it and open the location list
" window
lexpr ['F1:10:12:one', 'F1:20:14:two']
let w1_id = win_getid()
call setloclist(0, [], ' ',
\ {'lines': ['F1:10:12:one', 'F1:20:14:two'],
\ 'quickfixtextfunc':
\ {d -> map(getloclist(d.winid, {'id' : d.id,
\ 'items' : 1}).items[d.start_idx-1:d.end_idx-1],
\ "'Line ' .. v:val.lnum .. ', Col ' .. v:val.col")}})
lwindow
let w2_id = win_getid()
" create another window and a location list for it and open the location
" list window
topleft new
let w3_id = win_getid()
call setloclist(0, [], ' ',
\ {'lines': ['F2:30:32:eleven', 'F2:40:34:twelve'],
\ 'quickfixtextfunc':
\ {d -> map(getloclist(d.winid, {'id' : d.id,
\ 'items' : 1}).items[d.start_idx-1:d.end_idx-1],
\ "'Ligne ' .. v:val.lnum .. ', Colonne ' .. v:val.col")}})
lwindow
let w4_id = win_getid()
topleft new
lexpr ['F3:50:52:green', 'F3:60:54:blue']
let w5_id = win_getid()
" change the location list for some other window
call setloclist(0, [], 'r', {'lines': ['F3:55:56:aaa', 'F3:57:58:bbb']})
call setloclist(w1_id, [], 'r', {'lines': ['F1:62:63:bbb', 'F1:64:65:ccc']})
call setloclist(w3_id, [], 'r', {'lines': ['F2:76:77:ddd', 'F2:78:79:eee']})
call assert_equal(['Line 62, Col 63', 'Line 64, Col 65'],
\ getbufline(winbufnr(w2_id), 1, '$'))
call assert_equal(['Ligne 76, Colonne 77', 'Ligne 78, Colonne 79'],
\ getbufline(winbufnr(w4_id), 1, '$'))
call setloclist(w2_id, [], 'r', {'lines': ['F1:32:33:fff', 'F1:34:35:ggg']})
call setloclist(w4_id, [], 'r', {'lines': ['F2:46:47:hhh', 'F2:48:49:jjj']})
call assert_equal(['Line 32, Col 33', 'Line 34, Col 35'],
\ getbufline(winbufnr(w2_id), 1, '$'))
call assert_equal(['Ligne 46, Colonne 47', 'Ligne 48, Colonne 49'],
\ getbufline(winbufnr(w4_id), 1, '$'))
call win_gotoid(w5_id)
lwindow
call assert_equal(['F3|55 col 56| aaa', 'F3|57 col 58| bbb'],
\ getline(1, '$'))
%bw!
endfunc
" Running :lhelpgrep command more than once in a help window, doesn't jump to
" the help topic
func Test_lhelpgrep_from_help_window()
@@ -5281,7 +5366,42 @@ func Test_add_invalid_entry_with_qf_window()
call setqflist(['bb'], 'a')
call assert_equal(1, line('$'))
call assert_equal(['Xfile1|10| aa'], getline(1, '$'))
call assert_equal([{'lnum': 10, 'bufnr': bufnr('Xfile1'), 'col': 0, 'pattern': '', 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'module': '', 'text': 'aa'}], getqflist())
call assert_equal([{'lnum': 10 , 'end_lnum': 0 , 'bufnr': bufnr('Xfile1') , 'col': 0 , 'end_col': 0 , 'pattern': '' , 'valid': 1 , 'vcol': 0 , 'nr': -1 , 'type': '' , 'module': '' , 'text': 'aa'}] , getqflist())
call setqflist([{'lnum': 10 , 'bufnr': bufnr('Xfile1') , 'col': 0 , 'pattern': '' , 'valid': 1 , 'vcol': 0 , 'nr': -1 , 'type': '' , 'module': '' , 'text': 'aa'}] , 'r')
call assert_equal(1 , line('$'))
call assert_equal(['Xfile1|10| aa'] , getline(1 , '$'))
call assert_equal([{'lnum': 10 , 'end_lnum': 0 , 'bufnr': bufnr('Xfile1') , 'col': 0 , 'end_col': 0 , 'pattern': '' , 'valid': 1 , 'vcol': 0 , 'nr': -1 , 'type': '' , 'module': '' , 'text': 'aa'}] , getqflist())
call setqflist([{'lnum': 10 , 'end_lnum': 0 , 'bufnr': bufnr('Xfile1') , 'col': 0 , 'end_col': 0 , 'pattern': '' , 'valid': 1 , 'vcol': 0 , 'nr': -1 , 'type': '' , 'module': '' , 'text': 'aa'}] , 'r')
call assert_equal(1 , line('$'))
call assert_equal(['Xfile1|10| aa'] , getline(1 , '$'))
call assert_equal([{'lnum': 10 , 'end_lnum': 0 , 'bufnr': bufnr('Xfile1') , 'col': 0 , 'end_col': 0 , 'pattern': '' , 'valid': 1 , 'vcol': 0 , 'nr': -1 , 'type': '' , 'module': '' , 'text': 'aa'}] , getqflist())
call setqflist([{'lnum': 10 , 'end_lnum': -123 , 'bufnr': bufnr('Xfile1') , 'col': 0 , 'end_col': -456 , 'pattern': '' , 'valid': 1 , 'vcol': 0 , 'nr': -1 , 'type': '' , 'module': '' , 'text': 'aa'}] , 'r')
call assert_equal(1 , line('$'))
call assert_equal(['Xfile1|10| aa'] , getline(1 , '$'))
call assert_equal([{'lnum': 10 , 'end_lnum': -123 , 'bufnr': bufnr('Xfile1') , 'col': 0 , 'end_col': -456 , 'pattern': '' , 'valid': 1 , 'vcol': 0 , 'nr': -1 , 'type': '' , 'module': '' , 'text': 'aa'}] , getqflist())
call setqflist([{'lnum': 10 , 'end_lnum': -123 , 'bufnr': bufnr('Xfile1') , 'col': 666 , 'end_col': 0 , 'pattern': '' , 'valid': 1 , 'vcol': 0 , 'nr': -1 , 'type': '' , 'module': '' , 'text': 'aa'}] , 'r')
call assert_equal(1 , line('$'))
call assert_equal(['Xfile1|10 col 666| aa'] , getline(1 , '$'))
call assert_equal([{'lnum': 10 , 'end_lnum': -123 , 'bufnr': bufnr('Xfile1') , 'col': 666 , 'end_col': 0 , 'pattern': '' , 'valid': 1 , 'vcol': 0 , 'nr': -1 , 'type': '' , 'module': '' , 'text': 'aa'}] , getqflist())
call setqflist([{'lnum': 10 , 'end_lnum': -123 , 'bufnr': bufnr('Xfile1') , 'col': 666 , 'end_col': -456 , 'pattern': '' , 'valid': 1 , 'vcol': 0 , 'nr': -1 , 'type': '' , 'module': '' , 'text': 'aa'}] , 'r')
call assert_equal(1 , line('$'))
call assert_equal(['Xfile1|10 col 666| aa'] , getline(1 , '$'))
call assert_equal([{'lnum': 10 , 'end_lnum': -123 , 'bufnr': bufnr('Xfile1') , 'col': 666 , 'end_col': -456 , 'pattern': '' , 'valid': 1 , 'vcol': 0 , 'nr': -1 , 'type': '' , 'module': '' , 'text': 'aa'}] , getqflist())
call setqflist([{'lnum': 10 , 'end_lnum': -123 , 'bufnr': bufnr('Xfile1') , 'col': 666 , 'end_col': 222 , 'pattern': '' , 'valid': 1 , 'vcol': 0 , 'nr': -1 , 'type': '' , 'module': '' , 'text': 'aa'}] , 'r')
call assert_equal(1 , line('$'))
call assert_equal(['Xfile1|10 col 666-222| aa'] , getline(1 , '$'))
call assert_equal([{'lnum': 10 , 'end_lnum': -123 , 'bufnr': bufnr('Xfile1') , 'col': 666 , 'end_col': 222 , 'pattern': '' , 'valid': 1 , 'vcol': 0 , 'nr': -1 , 'type': '' , 'module': '' , 'text': 'aa'}] , getqflist())
call setqflist([{'lnum': 10 , 'end_lnum': 6 , 'bufnr': bufnr('Xfile1') , 'col': 666 , 'end_col': 222 , 'pattern': '' , 'valid': 1 , 'vcol': 0 , 'nr': -1 , 'type': '' , 'module': '' , 'text': 'aa'}] , 'r')
call assert_equal(1 , line('$'))
call assert_equal(['Xfile1|10-6 col 666-222| aa'] , getline(1 , '$'))
call assert_equal([{'lnum': 10 , 'end_lnum': 6 , 'bufnr': bufnr('Xfile1') , 'col': 666 , 'end_col': 222 , 'pattern': '' , 'valid': 1 , 'vcol': 0 , 'nr': -1 , 'type': '' , 'module': '' , 'text': 'aa'}] , getqflist())
cclose
endfunc
+23
View File
@@ -111,4 +111,27 @@ func Test_si_comment_line_continuation()
close!
endfunc
" When 'paste' is set, 'smartindent' should not take effect.
func Test_si_with_paste()
new
setlocal smartindent autoindent
set paste
" insert text that will trigger smartindent
exe "norm! i {\nif (x)\ni = 1;\n#define FOO 1\nj = 2;\n}"
exe "norm! Ok = 3;"
exe "norm! 4G>>"
call assert_equal([' {', 'if (x)', 'i = 1;', '#define FOO 1',
\ 'j = 2;', 'k = 3;', '}'], getline(1, '$'))
call assert_true(&smartindent)
set nopaste
%d _
exe "norm! i {\nif (x)\ni = 1;\n#define FOO 1\nj = 2;\n}"
exe "norm! Ok = 3;"
exe "norm! 4G>>"
call assert_equal([' {', "\t if (x)", "\t\t i = 1;",
\ '#define FOO 1', "\t\t j = 2;", "\t k = 3;", ' }'],
\ getline(1, '$'))
bw!
endfunc
" vim: shiftwidth=2 sts=2 expandtab
+2 -1
View File
@@ -1304,6 +1304,8 @@ func Test_write_in_vimrc()
endfunc
func Test_echo_true_in_cmd()
CheckNotGui
let lines =<< trim END
echo v:true
call writefile(['done'], 'Xresult')
@@ -1315,7 +1317,6 @@ func Test_echo_true_in_cmd()
endif
call delete('Xscript')
call delete('Xresult')
endfunc
" vim: shiftwidth=2 sts=2 expandtab
+7 -6
View File
@@ -837,15 +837,16 @@ func Test_ltag()
ltag third
call assert_equal('Xfoo', bufname(''))
call assert_equal(3, line('.'))
call assert_equal([{'lnum': 3, 'bufnr': bufnr('Xfoo'), 'col': 0,
\ 'pattern': '', 'valid': 1, 'vcol': 0, 'nr': 0, 'type': '',
\ 'module': '', 'text': 'third'}], getloclist(0))
call assert_equal([{'lnum': 3, 'end_lnum': 0, 'bufnr': bufnr('Xfoo'),
\ 'col': 0, 'end_col': 0, 'pattern': '', 'valid': 1, 'vcol': 0,
\ 'nr': 0, 'type': '', 'module': '', 'text': 'third'}], getloclist(0))
ltag second
call assert_equal(2, line('.'))
call assert_equal([{'lnum': 0, 'bufnr': bufnr('Xfoo'), 'col': 0,
\ 'pattern': '^\Vint second() {}\$', 'valid': 1, 'vcol': 0, 'nr': 0,
\ 'type': '', 'module': '', 'text': 'second'}], getloclist(0))
call assert_equal([{'lnum': 0, 'end_lnum': 0, 'bufnr': bufnr('Xfoo'),
\ 'col': 0, 'end_col': 0, 'pattern': '^\Vint second() {}\$',
\ 'valid': 1, 'vcol': 0, 'nr': 0, 'type': '', 'module': '',
\ 'text': 'second'}], getloclist(0))
call delete('Xtags')
call delete('Xfoo')
+36
View File
@@ -283,6 +283,29 @@ def Test_assign_unpack()
[v1, v2; _] = [1, 2, 3, 4, 5]
assert_equal(1, v1)
assert_equal(2, v2)
var a = 1
var b = 3
[a, b] += [2, 4]
assert_equal(3, a)
assert_equal(7, b)
[a, b] -= [1, 2]
assert_equal(2, a)
assert_equal(5, b)
[a, b] *= [3, 2]
assert_equal(6, a)
assert_equal(10, b)
[a, b] /= [2, 4]
assert_equal(3, a)
assert_equal(2, b)
[a, b] = [17, 15]
[a, b] %= [5, 3]
assert_equal(2, a)
assert_equal(0, b)
END
CheckDefAndScriptSuccess(lines)
@@ -1820,6 +1843,19 @@ def Test_assign_command_modifier()
CheckDefAndScriptSuccess(lines)
enddef
def Test_assign_alt_buf_register()
var lines =<< trim END
edit 'file_b1'
var b1 = bufnr()
edit 'file_b2'
var b2 = bufnr()
assert_equal(b1, bufnr('#'))
@# = b2
assert_equal(b2, bufnr('#'))
END
CheckDefAndScriptSuccess(lines)
enddef
def Test_script_funcref_case()
var lines =<< trim END
var Len = (s: string): number => len(s) + 1
+249
View File
@@ -141,6 +141,11 @@ def Test_add_blob()
CheckScriptSuccess(lines)
enddef
def Test_and()
CheckDefFailure(['echo and("x", 0x2)'], 'E1013: Argument 1: type mismatch, expected number but got string')
CheckDefFailure(['echo and(0x1, "x")'], 'E1013: Argument 2: type mismatch, expected number but got string')
enddef
def Test_append()
new
setline(1, range(3))
@@ -155,6 +160,22 @@ def Test_append()
bwipe!
enddef
def Test_argc()
CheckDefFailure(['echo argc("x")'], 'E1013: Argument 1: type mismatch, expected number but got string')
enddef
def Test_arglistid()
CheckDefFailure(['echo arglistid("x")'], 'E1013: Argument 1: type mismatch, expected number but got string')
CheckDefFailure(['echo arglistid(1, "y")'], 'E1013: Argument 2: type mismatch, expected number but got string')
CheckDefFailure(['echo arglistid("x", "y")'], 'E1013: Argument 1: type mismatch, expected number but got string')
enddef
def Test_argv()
CheckDefFailure(['echo argv("x")'], 'E1013: Argument 1: type mismatch, expected number but got string')
CheckDefFailure(['echo argv(1, "x")'], 'E1013: Argument 2: type mismatch, expected number but got string')
CheckDefFailure(['echo argv("x", "y")'], 'E1013: Argument 1: type mismatch, expected number but got string')
enddef
def Test_balloon_show()
CheckGui
CheckFeature balloon_eval
@@ -256,6 +277,10 @@ def Test_chdir()
assert_fails('chdir(true)', 'E1174')
enddef
def Test_clearmatches()
CheckDefFailure(['echo clearmatches("x")'], 'E1013: Argument 1: type mismatch, expected number but got string')
enddef
def Test_col()
new
setline(1, 'asdf')
@@ -311,6 +336,11 @@ def Test_cursor()
CheckDefExecAndScriptFailure(lines, 'E475:')
enddef
def Test_debugbreak()
CheckMSWindows
CheckDefFailure(['echo debugbreak("x")'], 'E1013: Argument 1: type mismatch, expected number but got string')
enddef
def Test_delete()
var res: bool = delete('doesnotexist')
assert_equal(true, res)
@@ -324,6 +354,18 @@ def Test_executable()
CheckDefExecFailure(['echo executable(true)'], 'E1174:')
enddef
def Test_execute()
var res = execute("echo 'hello'")
assert_equal("\nhello", res)
res = execute(["echo 'here'", "echo 'there'"])
assert_equal("\nhere\nthere", res)
CheckDefFailure(['echo execute(123)'], 'E1013: Argument 1: type mismatch, expected string but got number')
CheckDefFailure(['echo execute([123])'], 'E1013: Argument 1: type mismatch, expected list<string> but got list<number>')
CheckDefExecFailure(['echo execute(["xx", 123])'], 'E492')
CheckDefFailure(['echo execute("xx", 123)'], 'E1013: Argument 2: type mismatch, expected string but got number')
enddef
def Test_exepath()
CheckDefExecFailure(['echo exepath(true)'], 'E1174:')
CheckDefExecFailure(['echo exepath(v:null)'], 'E1174:')
@@ -520,6 +562,64 @@ def Test_flattennew()
CheckDefAndScriptFailure(lines, 'E1158:')
enddef
" Test for float functions argument type
def Test_float_funcs_args()
CheckFeature float
# acos()
CheckDefFailure(['echo acos("a")'], 'E1013: Argument 1: type mismatch, expected number but got string')
# asin()
CheckDefFailure(['echo asin("a")'], 'E1013: Argument 1: type mismatch, expected number but got string')
# atan()
CheckDefFailure(['echo atan("a")'], 'E1013: Argument 1: type mismatch, expected number but got string')
# atan2()
CheckDefFailure(['echo atan2("a", 1.1)'], 'E1013: Argument 1: type mismatch, expected number but got string')
CheckDefFailure(['echo atan2(1.2, "a")'], 'E1013: Argument 2: type mismatch, expected number but got string')
CheckDefFailure(['echo atan2(1.2)'], 'E119:')
# ceil()
CheckDefFailure(['echo ceil("a")'], 'E1013: Argument 1: type mismatch, expected number but got string')
# cos()
CheckDefFailure(['echo cos("a")'], 'E1013: Argument 1: type mismatch, expected number but got string')
# cosh()
CheckDefFailure(['echo cosh("a")'], 'E1013: Argument 1: type mismatch, expected number but got string')
# exp()
CheckDefFailure(['echo exp("a")'], 'E1013: Argument 1: type mismatch, expected number but got string')
# float2nr()
CheckDefFailure(['echo float2nr("a")'], 'E1013: Argument 1: type mismatch, expected number but got string')
# floor()
CheckDefFailure(['echo floor("a")'], 'E1013: Argument 1: type mismatch, expected number but got string')
# fmod()
CheckDefFailure(['echo fmod(1.1, "a")'], 'E1013: Argument 2: type mismatch, expected number but got string')
CheckDefFailure(['echo fmod("a", 1.1)'], 'E1013: Argument 1: type mismatch, expected number but got string')
CheckDefFailure(['echo fmod(1.1)'], 'E119:')
# isinf()
CheckDefFailure(['echo isinf("a")'], 'E1013: Argument 1: type mismatch, expected number but got string')
# isnan()
CheckDefFailure(['echo isnan("a")'], 'E1013: Argument 1: type mismatch, expected number but got string')
# log()
CheckDefFailure(['echo log("a")'], 'E1013: Argument 1: type mismatch, expected number but got string')
# log10()
CheckDefFailure(['echo log10("a")'], 'E1013: Argument 1: type mismatch, expected number but got string')
# pow()
CheckDefFailure(['echo pow("a", 1.1)'], 'E1013: Argument 1: type mismatch, expected number but got string')
CheckDefFailure(['echo pow(1.1, "a")'], 'E1013: Argument 2: type mismatch, expected number but got string')
CheckDefFailure(['echo pow(1.1)'], 'E119:')
# round()
CheckDefFailure(['echo round("a")'], 'E1013: Argument 1: type mismatch, expected number but got string')
# sin()
CheckDefFailure(['echo sin("a")'], 'E1013: Argument 1: type mismatch, expected number but got string')
# sinh()
CheckDefFailure(['echo sinh("a")'], 'E1013: Argument 1: type mismatch, expected number but got string')
# sqrt()
CheckDefFailure(['echo sqrt("a")'], 'E1013: Argument 1: type mismatch, expected number but got string')
# tan()
CheckDefFailure(['echo tan("a")'], 'E1013: Argument 1: type mismatch, expected number but got string')
# tanh()
CheckDefFailure(['echo tanh("a")'], 'E1013: Argument 1: type mismatch, expected number but got string')
# trunc()
CheckDefFailure(['echo trunc("a")'], 'E1013: Argument 1: type mismatch, expected number but got string')
enddef
def Test_fnamemodify()
CheckDefSuccess(['echo fnamemodify(test_null_string(), ":p")'])
CheckDefSuccess(['echo fnamemodify("", ":p")'])
@@ -640,6 +740,20 @@ def Test_getcompletion()
set wildignore&
enddef
def Test_getcurpos()
CheckDefFailure(['echo getcursorcharpos("x")'], 'E1013: Argument 1: type mismatch, expected number but got string')
enddef
def Test_getcursorcharpos()
CheckDefFailure(['echo getcursorcharpos("x")'], 'E1013: Argument 1: type mismatch, expected number but got string')
enddef
def Test_getcwd()
CheckDefFailure(['echo getcwd("x")'], 'E1013: Argument 1: type mismatch, expected number but got string')
CheckDefFailure(['echo getcwd("x", 1)'], 'E1013: Argument 1: type mismatch, expected number but got string')
CheckDefFailure(['echo getcwd(1, "x")'], 'E1013: Argument 2: type mismatch, expected number but got string')
enddef
def Test_getloclist_return_type()
var l = getloclist(1)
l->assert_equal([])
@@ -680,6 +794,16 @@ def Test_getftype()
CheckDefExecFailure(['echo getftype(v:null)'], 'E1174:')
enddef
def Test_getjumplist()
CheckDefFailure(['echo getjumplist("x")'], 'E1013: Argument 1: type mismatch, expected number but got string')
CheckDefFailure(['echo getjumplist("x", 1)'], 'E1013: Argument 1: type mismatch, expected number but got string')
CheckDefFailure(['echo getjumplist(1, "x")'], 'E1013: Argument 2: type mismatch, expected number but got string')
enddef
def Test_getmatches()
CheckDefFailure(['echo getmatches("x")'], 'E1013: Argument 1: type mismatch, expected number but got string')
enddef
def Test_getqflist_return_type()
var l = getqflist()
l->assert_equal([])
@@ -715,6 +839,22 @@ def Test_getregtype()
assert_fails('getregtype("ab")', 'E1162:')
enddef
def Test_gettabinfo()
CheckDefFailure(['echo gettabinfo("x")'], 'E1013: Argument 1: type mismatch, expected number but got string')
enddef
def Test_gettagstack()
CheckDefFailure(['echo gettagstack("x")'], 'E1013: Argument 1: type mismatch, expected number but got string')
enddef
def Test_getwininfo()
CheckDefFailure(['echo getwininfo("x")'], 'E1013: Argument 1: type mismatch, expected number but got string')
enddef
def Test_getwinpos()
CheckDefFailure(['echo getwinpos("x")'], 'E1013: Argument 1: type mismatch, expected number but got string')
enddef
def Test_glob()
glob('runtest.vim', true, true, true)->assert_equal(['runtest.vim'])
enddef
@@ -727,6 +867,12 @@ def Test_has()
has('eval', true)->assert_equal(1)
enddef
def Test_haslocaldir()
CheckDefFailure(['echo haslocaldir("x")'], 'E1013: Argument 1: type mismatch, expected number but got string')
CheckDefFailure(['echo haslocaldir("x", 1)'], 'E1013: Argument 1: type mismatch, expected number but got string')
CheckDefFailure(['echo haslocaldir(1, "x")'], 'E1013: Argument 2: type mismatch, expected number but got string')
enddef
def Test_hasmapto()
hasmapto('foobar', 'i', true)->assert_equal(0)
iabbrev foo foobar
@@ -778,6 +924,10 @@ def Test_insert()
CheckDefFailure(['insert([2, 3], 1, "x")'], 'E1013: Argument 3: type mismatch, expected number but got string', 1)
enddef
def Test_invert()
CheckDefFailure(['echo invert("x")'], 'E1013: Argument 1: type mismatch, expected number but got string')
enddef
def Test_keys_return_type()
const var: list<string> = {a: 1, b: 2}->keys()
var->assert_equal(['a', 'b'])
@@ -800,6 +950,10 @@ def SID(): number
->str2nr()
enddef
def Test_listener_remove()
CheckDefFailure(['echo listener_remove("x")'], 'E1013: Argument 1: type mismatch, expected number but got string')
enddef
def Test_map_function_arg()
var lines =<< trim END
def MapOne(i: number, v: string): string
@@ -902,6 +1056,16 @@ def Test_map_failure()
delete('Xtmpfile')
enddef
def Test_matcharg()
CheckDefFailure(['echo matcharg("x")'], 'E1013: Argument 1: type mismatch, expected number but got string')
enddef
def Test_matchdelete()
CheckDefFailure(['echo matchdelete("x")'], 'E1013: Argument 1: type mismatch, expected number but got string')
CheckDefFailure(['echo matchdelete("x", 1)'], 'E1013: Argument 1: type mismatch, expected number but got string')
CheckDefFailure(['echo matchdelete(1, "x")'], 'E1013: Argument 2: type mismatch, expected number but got string')
enddef
def Test_max()
g:flag = true
var l1: list<number> = g:flag
@@ -934,6 +1098,11 @@ def Test_nr2char()
nr2char(97, true)->assert_equal('a')
enddef
def Test_or()
CheckDefFailure(['echo or("x", 0x2)'], 'E1013: Argument 1: type mismatch, expected number but got string')
CheckDefFailure(['echo or(0x1, "x")'], 'E1013: Argument 2: type mismatch, expected number but got string')
enddef
def Test_readdir()
eval expand('sautest')->readdir((e) => e[0] !=# '.')
eval expand('sautest')->readdirex((e) => e.name[0] !=# '.')
@@ -983,6 +1152,26 @@ def Test_reverse_return_type()
res->assert_equal(6)
enddef
def Test_screenattr()
CheckDefFailure(['echo screenattr("x", 1)'], 'E1013: Argument 1: type mismatch, expected number but got string')
CheckDefFailure(['echo screenattr(1, "x")'], 'E1013: Argument 2: type mismatch, expected number but got string')
enddef
def Test_screenchar()
CheckDefFailure(['echo screenchar("x", 1)'], 'E1013: Argument 1: type mismatch, expected number but got string')
CheckDefFailure(['echo screenchar(1, "x")'], 'E1013: Argument 2: type mismatch, expected number but got string')
enddef
def Test_screenchars()
CheckDefFailure(['echo screenchars("x", 1)'], 'E1013: Argument 1: type mismatch, expected number but got string')
CheckDefFailure(['echo screenchars(1, "x")'], 'E1013: Argument 2: type mismatch, expected number but got string')
enddef
def Test_screenstring()
CheckDefFailure(['echo screenstring("x", 1)'], 'E1013: Argument 1: type mismatch, expected number but got string')
CheckDefFailure(['echo screenstring(1, "x")'], 'E1013: Argument 2: type mismatch, expected number but got string')
enddef
def Test_search()
new
setline(1, ['foo', 'bar'])
@@ -1145,6 +1334,10 @@ def Test_setbufvar()
getbufvar('%', 'myvar')->assert_equal(123)
enddef
def Test_setcmdpos()
CheckDefFailure(['echo setcmdpos("x")'], 'E1013: Argument 1: type mismatch, expected number but got string')
enddef
def Test_setloclist()
var items = [{filename: '/tmp/file', lnum: 1, valid: true}]
var what = {items: items}
@@ -1160,6 +1353,10 @@ def Test_setreg()
assert_fails('setreg("ab", 0)', 'E1162:')
enddef
def Test_shiftwidth()
CheckDefFailure(['echo shiftwidth("x")'], 'E1013: Argument 1: type mismatch, expected number but got string')
enddef
def Test_slice()
assert_equal('12345', slice('012345', 1))
assert_equal('123', slice('012345', 1, 4))
@@ -1297,6 +1494,20 @@ def Test_timer_paused()
timer_stop(id)
enddef
def Test_tolower()
CheckDefFailure(['echo tolower(1)'], 'E1013: Argument 1: type mismatch, expected string but got number')
enddef
def Test_toupper()
CheckDefFailure(['echo toupper(1)'], 'E1013: Argument 1: type mismatch, expected string but got number')
enddef
def Test_tr()
CheckDefFailure(['echo tr(1, "a", "b")'], 'E1013: Argument 1: type mismatch, expected string but got number')
CheckDefFailure(['echo tr("a", 1, "b")'], 'E1013: Argument 2: type mismatch, expected string but got number')
CheckDefFailure(['echo tr("a", "a", 1)'], 'E1013: Argument 3: type mismatch, expected string but got number')
enddef
def Test_win_execute()
assert_equal("\n" .. winnr(), win_execute(win_getid(), 'echo winnr()'))
assert_equal('', win_execute(342343, 'echo winnr()'))
@@ -1326,7 +1537,45 @@ def Test_winsaveview()
CheckDefAndScriptFailure(lines, 'E1012: Type mismatch; expected list<number> but got dict<number>', 1)
enddef
def Test_win_gettype()
CheckDefFailure(['echo win_gettype("x")'], 'E1013: Argument 1: type mismatch, expected number but got string')
enddef
def Test_win_gotoid()
CheckDefFailure(['echo win_gotoid("x")'], 'E1013: Argument 1: type mismatch, expected number but got string')
enddef
def Test_win_id2tabwin()
CheckDefFailure(['echo win_id2tabwin("x")'], 'E1013: Argument 1: type mismatch, expected number but got string')
enddef
def Test_win_id2win()
CheckDefFailure(['echo win_id2win("x")'], 'E1013: Argument 1: type mismatch, expected number but got string')
enddef
def Test_win_screenpos()
CheckDefFailure(['echo win_screenpos("x")'], 'E1013: Argument 1: type mismatch, expected number but got string')
enddef
def Test_winbufnr()
CheckDefFailure(['echo winbufnr("x")'], 'E1013: Argument 1: type mismatch, expected number but got string')
enddef
def Test_winheight()
CheckDefFailure(['echo winheight("x")'], 'E1013: Argument 1: type mismatch, expected number but got string')
enddef
def Test_winlayout()
CheckDefFailure(['echo winlayout("x")'], 'E1013: Argument 1: type mismatch, expected number but got string')
enddef
def Test_winwidth()
CheckDefFailure(['echo winwidth("x")'], 'E1013: Argument 1: type mismatch, expected number but got string')
enddef
def Test_xor()
CheckDefFailure(['echo xor("x", 0x2)'], 'E1013: Argument 1: type mismatch, expected number but got string')
CheckDefFailure(['echo xor(0x1, "x")'], 'E1013: Argument 2: type mismatch, expected number but got string')
enddef
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
+31
View File
@@ -452,6 +452,37 @@ def Test_disassemble_list_assign()
res)
enddef
def s:ListAssignWithOp()
var a = 2
var b = 3
[a, b] += [4, 5]
enddef
def Test_disassemble_list_assign_with_op()
var res = execute('disass s:ListAssignWithOp')
assert_match('<SNR>\d*_ListAssignWithOp\_s*' ..
'var a = 2\_s*' ..
'\d STORE 2 in $0\_s*' ..
'var b = 3\_s*' ..
'\d STORE 3 in $1\_s*' ..
'\[a, b\] += \[4, 5\]\_s*' ..
'\d\+ PUSHNR 4\_s*' ..
'\d\+ PUSHNR 5\_s*' ..
'\d\+ NEWLIST size 2\_s*' ..
'\d\+ CHECKLEN 2\_s*' ..
'\d\+ LOAD $0\_s*' ..
'\d\+ ITEM 0 with op\_s*' ..
'\d\+ OPNR +\_s*' ..
'\d\+ STORE $0\_s*' ..
'\d\+ LOAD $1\_s*' ..
'\d\+ ITEM 1 with op\_s*' ..
'\d\+ OPNR +\_s*' ..
'\d\+ STORE $1\_s*' ..
'\d\+ DROP\_s*' ..
'\d\+ RETURN void',
res)
enddef
def s:ListAdd()
var l: list<number> = []
add(l, 123)
+7 -5
View File
@@ -2340,7 +2340,7 @@ def Test_expr7_dict()
CheckScriptFailure(['vim9script', "var x = {xxx: 1,"], 'E723:', 2)
CheckDefAndScriptFailure2(["var x = {['a']: xxx}"], 'E1001:', 'E121:', 1)
CheckDefAndScriptFailure(["var x = {a: 1, a: 2}"], 'E721:', 1)
CheckDefExecAndScriptFailure2(["var x = g:anint.member"], 'E715:', 'E15:', 1)
CheckDefExecAndScriptFailure2(["var x = g:anint.member"], 'E715:', 'E488:', 1)
CheckDefExecAndScriptFailure(["var x = g:dict_empty.member"], 'E716:', 1)
CheckDefExecAndScriptFailure(['var x: dict<number> = {a: 234, b: "1"}'], 'E1012:', 1)
@@ -2943,7 +2943,9 @@ def Test_expr7_method_call()
loclist->setloclist(0)
assert_equal([{bufnr: bufnr,
lnum: 42,
end_lnum: 0,
col: 17,
end_col: 0,
text: 'wrong',
pattern: '',
valid: 1,
@@ -3052,7 +3054,7 @@ func Test_expr7_fails()
call CheckDefAndScriptFailure2(["var x = [notfound]"], "E1001:", 'E121:', 1)
call CheckDefAndScriptFailure2(["var X = () => 123)"], "E488:", 'E15:', 1)
call CheckDefAndScriptFailure(["var X = () => 123)"], 'E488:', 1)
call CheckDefAndScriptFailure(["var x = 123->((x) => x + 5)"], "E107:", 1)
call CheckDefAndScriptFailure(["var x = &notexist"], 'E113:', 1)
@@ -3070,7 +3072,7 @@ func Test_expr7_fails()
call CheckDefExecAndScriptFailure(["var x = +g:alist"], 'E745:', 1)
call CheckDefExecAndScriptFailure(["var x = +g:adict"], 'E728:', 1)
call CheckDefAndScriptFailure2(["var x = ''", "var y = x.memb"], 'E715:', 'E15:', 2)
call CheckDefAndScriptFailure2(["var x = ''", "var y = x.memb"], 'E715:', 'E488:', 2)
call CheckDefAndScriptFailure2(["'yes'->", "Echo()"], 'E488: Trailing characters: ->', 'E260: Missing name after ->', 1)
@@ -3354,8 +3356,8 @@ func Test_expr7_trailing_fails()
endfunc
func Test_expr_fails()
call CheckDefAndScriptFailure2(["var x = '1'is2"], 'E488:', 'E15:', 1)
call CheckDefAndScriptFailure2(["var x = '1'isnot2"], 'E488:', 'E15:', 1)
call CheckDefAndScriptFailure(["var x = '1'is2"], 'E488:', 1)
call CheckDefAndScriptFailure(["var x = '1'isnot2"], 'E488:', 1)
call CheckDefAndScriptFailure2(["CallMe ('yes')"], 'E476:', 'E492:', 1)
+32
View File
@@ -90,6 +90,24 @@ def Test_compile_error_in_called_function()
CheckScriptFailureList(lines, ['E1012:', 'E1191:'])
enddef
def Test_wrong_function_name()
var lines =<< trim END
vim9script
func _Foo()
echo 'foo'
endfunc
END
CheckScriptFailure(lines, 'E128:')
lines =<< trim END
vim9script
def _Foo()
echo 'foo'
enddef
END
CheckScriptFailure(lines, 'E128:')
enddef
def Test_autoload_name_mismatch()
var dir = 'Xdir/autoload'
mkdir(dir, 'p')
@@ -987,6 +1005,20 @@ def Test_pass_legacy_lambda_to_def_func()
Foo()
END
CheckScriptSuccess(lines)
lines =<< trim END
vim9script
def g:TestFunc(f: func())
enddef
legacy call g:TestFunc({-> 0})
delfunc g:TestFunc
def g:TestFunc(f: func(number))
enddef
legacy call g:TestFunc({nr -> 0})
delfunc g:TestFunc
END
CheckScriptSuccess(lines)
enddef
" Default arg and varargs
+23 -3
View File
@@ -3212,7 +3212,7 @@ def Test_vim9_comment_not_compiled()
'if 1# comment3',
' echo "yes"',
'endif',
], 'E15:')
], 'E488:')
CheckScriptFailure([
'vim9script',
@@ -3221,7 +3221,7 @@ def Test_vim9_comment_not_compiled()
'elseif 2#comment',
' echo "no"',
'endif',
], 'E15:')
], 'E488:')
CheckScriptSuccess([
'vim9script',
@@ -3231,7 +3231,7 @@ def Test_vim9_comment_not_compiled()
CheckScriptFailure([
'vim9script',
'var v = 1# comment6',
], 'E15:')
], 'E488:')
CheckScriptSuccess([
'vim9script',
@@ -3937,6 +3937,26 @@ def Test_mapping_line_number()
delfunc g:FuncA
enddef
def Test_option_modifier()
var lines =<< trim END
set hlsearch & hlsearch !
call assert_equal(1, &hlsearch)
END
CheckScriptSuccess(lines)
lines =<< trim END
vim9script
set hlsearch &
END
CheckScriptFailure(lines, 'E518:')
lines =<< trim END
vim9script
set hlsearch & hlsearch !
END
CheckScriptFailure(lines, 'E518:')
enddef
" Keep this last, it messes up highlighting.
def Test_substitute_cmd()
new
+381 -3
View File
@@ -4,7 +4,7 @@ source check.vim
source term_util.vim
source shared.vim
function Test_viminfo_read_and_write()
func Test_viminfo_read_and_write()
" First clear 'history', so that "hislen" is zero. Then set it again,
" simulating Vim starting up.
set history=0
@@ -12,6 +12,7 @@ function Test_viminfo_read_and_write()
set history=1000
call histdel(':')
let @/=''
let lines = [
\ '# comment line',
\ '*encoding=utf-8',
@@ -62,6 +63,7 @@ func Test_global_vars()
let g:MY_GLOBAL_NULL = test_null
let test_none = v:none
let g:MY_GLOBAL_NONE = test_none
let g:MY_GLOBAL_FUNCREF = function('min')
set viminfo='100,<50,s10,h,!,nviminfo
wv! Xviminfo
@@ -76,6 +78,7 @@ func Test_global_vars()
unlet g:MY_GLOBAL_TRUE
unlet g:MY_GLOBAL_NULL
unlet g:MY_GLOBAL_NONE
unlet g:MY_GLOBAL_FUNCREF
rv! Xviminfo
call assert_equal("Vim Editor", g:MY_GLOBAL_STRING)
@@ -88,6 +91,37 @@ func Test_global_vars()
call assert_equal(test_true, g:MY_GLOBAL_TRUE)
call assert_equal(test_null, g:MY_GLOBAL_NULL)
call assert_equal(test_none, g:MY_GLOBAL_NONE)
call assert_false(exists("g:MY_GLOBAL_FUNCREF"))
" When reading global variables from viminfo, if a variable cannot be
" modified, then the value should not be changed.
unlet g:MY_GLOBAL_STRING
unlet g:MY_GLOBAL_NUM
unlet g:MY_GLOBAL_FLOAT
unlet g:MY_GLOBAL_DICT
unlet g:MY_GLOBAL_LIST
unlet g:MY_GLOBAL_BLOB
const g:MY_GLOBAL_STRING = 'New Value'
const g:MY_GLOBAL_NUM = 987
const g:MY_GLOBAL_FLOAT = 1.16
const g:MY_GLOBAL_DICT = {'editor': 'vim'}
const g:MY_GLOBAL_LIST = [5, 7, 13]
const g:MY_GLOBAL_BLOB = 0zDEADBEEF
call assert_fails('rv! Xviminfo', 'E741:')
call assert_equal('New Value', g:MY_GLOBAL_STRING)
call assert_equal(987, g:MY_GLOBAL_NUM)
call assert_equal(1.16, g:MY_GLOBAL_FLOAT)
call assert_equal({'editor': 'vim'}, g:MY_GLOBAL_DICT)
call assert_equal([5, 7 , 13], g:MY_GLOBAL_LIST)
call assert_equal(0zDEADBEEF, g:MY_GLOBAL_BLOB)
unlet g:MY_GLOBAL_STRING
unlet g:MY_GLOBAL_NUM
unlet g:MY_GLOBAL_FLOAT
unlet g:MY_GLOBAL_DICT
unlet g:MY_GLOBAL_LIST
unlet g:MY_GLOBAL_BLOB
" Test for invalid values for a blob, list, dict in a viminfo file
call writefile([
@@ -97,7 +131,7 @@ func Test_global_vars()
\ "!GLOB_BLOB_4\tBLO\t0z12 ab",
\ "!GLOB_LIST_1\tLIS\t1 2",
\ "!GLOB_DICT_1\tDIC\t1 2"], 'Xviminfo')
call assert_fails('rv! Xviminfo', 'E15:')
call assert_fails('rv! Xviminfo', 'E488:')
call assert_equal('123', g:GLOB_BLOB_1)
call assert_equal(1, type(g:GLOB_BLOB_1))
call assert_equal('012', g:GLOB_BLOB_2)
@@ -199,7 +233,26 @@ func Test_cmdline_history()
call assert_equal("echo " . long800, histget(':', -2))
call assert_equal("echo 'one'", histget(':', -3))
" If the value for the '/' or ':' or '@' field in 'viminfo' is zero, then
" the corresponding history entries are not saved.
set viminfo='100,/0,:0,@0,<50,s10,h,!,nviminfo
call histdel('/')
call histdel(':')
call histdel('@')
call histadd('/', 'foo')
call histadd(':', 'bar')
call histadd('@', 'baz')
wviminfo! Xviminfo
call histdel('/')
call histdel(':')
call histdel('@')
rviminfo! Xviminfo
call assert_equal('', histget('/'))
call assert_equal('', histget(':'))
call assert_equal('', histget('@'))
call delete('Xviminfo')
set viminfo&vim
endfunc
func Test_cmdline_history_order()
@@ -315,7 +368,33 @@ func Test_viminfo_registers()
let len += 1
endwhile
" If the maximum number of lines saved for a register ('<' in 'viminfo') is
" zero, then register values should not be saved.
let @a = 'abc'
set viminfo='100,<0,s10,h,!,nviminfo
wviminfo Xviminfo
let @a = 'xyz'
rviminfo! Xviminfo
call assert_equal('xyz', @a)
" repeat the test with '"' instead of '<'
let @b = 'def'
set viminfo='100,\"0,s10,h,!,nviminfo
wviminfo Xviminfo
let @b = 'rst'
rviminfo! Xviminfo
call assert_equal('rst', @b)
" If the maximum size of an item ('s' in 'viminfo') is zero, then register
" values should not be saved.
let @c = '123'
set viminfo='100,<20,s0,h,!,nviminfo
wviminfo Xviminfo
let @c = '456'
rviminfo! Xviminfo
call assert_equal('456', @c)
call delete('Xviminfo')
set viminfo&vim
endfunc
func Test_viminfo_marks()
@@ -510,6 +589,35 @@ func Test_viminfo_bad_syntax()
call delete('Xviminfo')
endfunc
func Test_viminfo_bad_syntax2()
let lines = []
call add(lines, '|1,4')
" bad viminfo syntax for history barline
call add(lines, '|2') " invalid number of fields in a history barline
call add(lines, '|2,9,1,1,"x"') " invalid value for the history type
call add(lines, '|2,0,,1,"x"') " no timestamp
call add(lines, '|2,0,1,1,10') " non-string text
" bad viminfo syntax for register barline
call add(lines, '|3') " invalid number of fields in a register barline
call add(lines, '|3,1,1,1,1,,1,"x"') " missing width field
call add(lines, '|3,0,80,1,1,1,1,"x"') " invalid register number
call add(lines, '|3,0,10,5,1,1,1,"x"') " invalid register type
call add(lines, '|3,0,10,1,20,1,1,"x"') " invalid line count
call add(lines, '|3,0,10,1,0,1,1') " zero line count
" bad viminfo syntax for mark barline
call add(lines, '|4') " invalid number of fields in a mark barline
call add(lines, '|4,1,1,1,1,1') " invalid value for file name
call add(lines, '|4,20,1,1,1,"x"') " invalid value for file name
call add(lines, '|4,49,0,1,1,"x"') " invalid value for line number
call writefile(lines, 'Xviminfo')
rviminfo Xviminfo
call delete('Xviminfo')
endfunc
func Test_viminfo_file_marks()
silent! bwipe test_viminfo.vim
silent! bwipe Xviminfo
@@ -664,6 +772,7 @@ func Test_viminfo_bufferlist()
" If there are arguments, then :rviminfo doesn't read the buffer list.
" Need to delete all the arguments for :rviminfo to work.
%argdelete
set viminfo&vim
edit Xfile1
edit Xfile2
@@ -684,9 +793,42 @@ func Test_viminfo_bufferlist()
call assert_equal('Xfile1', bufname(l[1].bufnr))
call assert_equal('Xfile2', bufname(l[2].bufnr))
" The quickfix, terminal, unlisted, unnamed buffers are not stored in the
" viminfo file
%bw!
edit Xfile1
new
setlocal nobuflisted
new
copen
if has('terminal')
terminal
endif
wviminfo! Xviminfo
%bwipe!
rviminfo Xviminfo
let l = getbufinfo()
call assert_equal(2, len(l))
call assert_true(bufexists('Xfile1'))
" If a count is specified for '%', then only that many buffers should be
" stored in the viminfo file.
%bw!
set viminfo&vim
new Xbuf1
new Xbuf2
set viminfo+=%1
wviminfo! Xviminfo
%bwipe!
rviminfo! Xviminfo
let l = getbufinfo()
call assert_equal(2, len(l))
call assert_true(bufexists('Xbuf1'))
call assert_false(bufexists('Xbuf2'))
call delete('Xviminfo')
%bwipe
set viminfo-=%
set viminfo&vim
endfunc
" Test for errors in a viminfo file
@@ -747,6 +889,12 @@ func Test_viminfo_registers_old()
\ ' Vim',
\ '"a CHAR 0',
\ ' red',
\ '"c BLOCK 0',
\ ' a',
\ ' d',
\ '"d LINE 0',
\ ' abc',
\ ' def',
\ '"m@ CHAR 0',
\ " :echo 'Hello'\<CR>",
\ "",
@@ -760,7 +908,12 @@ func Test_viminfo_registers_old()
silent! normal @t
rviminfo! Xviminfo
call assert_equal('red', getreg('a'))
call assert_equal("v", getregtype('a'))
call assert_equal('two', getreg('b'))
call assert_equal("a\nd", getreg('c'))
call assert_equal("\<C-V>1", getregtype('c'))
call assert_equal("abc\ndef\n", getreg('d'))
call assert_equal("V", getregtype('d'))
call assert_equal(":echo 'Hello'\<CR>", getreg('m'))
call assert_equal('Vim', getreg('"'))
call assert_equal("\nHello", execute('normal @@'))
@@ -811,6 +964,7 @@ func Test_viminfo_perm()
" Try to write the viminfo to a directory
call mkdir('Xdir')
call assert_fails('wviminfo Xdir', 'E137:')
call assert_fails('rviminfo Xdir', 'E195:')
call delete('Xdir', 'rf')
endfunc
@@ -914,4 +1068,228 @@ func Test_viminfo_oldfiles_newfile()
let &viminfofile = save_viminfofile
endfunc
" When writing CTRL-V or "\n" to a viminfo file, it is converted to CTRL-V
" CTRL-V and CTRL-V n respectively.
func Test_viminfo_with_Ctrl_V()
silent! exe "normal! /\<C-V>\<C-V>\n"
wviminfo Xviminfo
call assert_notequal(-1, readfile('Xviminfo')->index("?/\<C-V>\<C-V>"))
let @/ = 'abc'
rviminfo! Xviminfo
call assert_equal("\<C-V>", @/)
silent! exe "normal! /\<C-V>\<C-J>\n"
wviminfo Xviminfo
call assert_notequal(-1, readfile('Xviminfo')->index("?/\<C-V>n"))
let @/ = 'abc'
rviminfo! Xviminfo
call assert_equal("\n", @/)
call delete('Xviminfo')
endfunc
" Test for the 'r' field in 'viminfo' (removal media)
func Test_viminfo_removable_media()
CheckUnix
if !isdirectory('/tmp') || getftype('/tmp') != 'dir'
return
endif
let save_viminfo = &viminfo
set viminfo+=r/tmp
edit /tmp/Xvima1b2c3
wviminfo Xviminfo
let matches = readfile('Xviminfo')->filter("v:val =~ 'Xvima1b2c3'")
call assert_equal(0, matches->len())
let &viminfo = save_viminfo
call delete('Xviminfo')
endfunc
" Test for the 'h' flag in 'viminfo'. If 'h' is not present, then the last
" search pattern read from 'viminfo' should be highlighted with 'hlsearch'.
" If 'h' is present, then the last search pattern should not be highlighted.
func Test_viminfo_hlsearch()
set viminfo&vim
new
call setline(1, ['one two three'])
" save the screen attribute for the Search highlighted text and the normal
" text for later comparison
set hlsearch
let @/ = 'three'
redraw!
let hiSearch = screenattr(1, 9)
let hiNormal = screenattr(1, 1)
set viminfo-=h
let @/='two'
wviminfo! Xviminfo
let @/='one'
rviminfo! Xviminfo
redraw!
call assert_equal(hiSearch, screenattr(1, 5))
call assert_equal(hiSearch, screenattr(1, 6))
call assert_equal(hiSearch, screenattr(1, 7))
set viminfo+=h
let @/='two'
wviminfo! Xviminfo
let @/='one'
rviminfo! Xviminfo
redraw!
call assert_equal(hiNormal, screenattr(1, 5))
call assert_equal(hiNormal, screenattr(1, 6))
call assert_equal(hiNormal, screenattr(1, 7))
call delete('Xviminfo')
set hlsearch& viminfo&vim
bw!
endfunc
" Test for restoring the magicness of the last search pattern from the viminfo
" file.
func Test_viminfo_last_spat_magic()
set viminfo&vim
new
call setline(1, ' one abc a.c')
" restore 'nomagic'
set nomagic
exe "normal gg/a.c\<CR>"
wviminfo! Xviminfo
set magic
exe "normal gg/one\<CR>"
rviminfo! Xviminfo
exe "normal! gg/\<CR>"
call assert_equal(10, col('.'))
" restore 'magic'
set magic
exe "normal gg/a.c\<CR>"
wviminfo! Xviminfo
set nomagic
exe "normal gg/one\<CR>"
rviminfo! Xviminfo
exe "normal! gg/\<CR>"
call assert_equal(6, col('.'))
call delete('Xviminfo')
set viminfo&vim magic&
bw!
endfunc
" Test for restoring the smartcase of the last search pattern from the viminfo
" file.
func Test_viminfo_last_spat_smartcase()
new
call setline(1, ' one abc Abc')
set ignorecase smartcase
" Searching with * should disable smartcase
exe "normal! gg$b*"
wviminfo! Xviminfo
exe "normal gg/one\<CR>"
rviminfo! Xviminfo
exe "normal! gg/\<CR>"
call assert_equal(6, col('.'))
call delete('Xviminfo')
set ignorecase& smartcase& viminfo&
bw!
endfunc
" Test for restoring the last search pattern with a line or character offset
" from the viminfo file.
func Test_viminfo_last_spat_offset()
new
call setline(1, ['one', 'two', 'three', 'four', 'five'])
" line offset
exe "normal! /two/+2\<CR>"
wviminfo! Xviminfo
exe "normal gg/five\<CR>"
rviminfo! Xviminfo
exe "normal! gg/\<CR>"
call assert_equal(4, line('.'))
" character offset
exe "normal! gg/^th/e+2\<CR>"
wviminfo! Xviminfo
exe "normal gg/two\<CR>"
rviminfo! Xviminfo
exe "normal! gg/\<CR>"
call assert_equal([3, 4], [line('.'), col('.')])
call delete('Xviminfo')
bw!
endfunc
" Test for saving and restoring the last executed register (@ command)
" from the viminfo file
func Test_viminfo_last_exec_reg()
let g:val = 1
let @a = ":let g:val += 1\n"
normal! @a
wviminfo! Xviminfo
let @b = ''
normal! @b
rviminfo! Xviminfo
normal @@
call assert_equal(3, g:val)
call delete('Xviminfo')
endfunc
" Test for merging file marks in a viminfo file
func Test_viminfo_merge_file_marks()
for [f, l, t] in [['a.txt', 5, 10], ['b.txt', 10, 20]]
call test_settime(t)
exe 'edit ' .. f
call setline(1, range(1, 20))
exe l . 'mark a'
wviminfo Xviminfo
bw!
endfor
call test_settime(30)
for [f, l] in [['a.txt', 5], ['b.txt', 10]]
exe 'edit ' .. f
rviminfo! Xviminfo
call assert_equal(l, line("'a"))
bw!
endfor
call delete('Xviminfo')
call test_settime(0)
endfunc
" Test for merging file marks from a old viminfo file
func Test_viminfo_merge_old_filemarks()
let lines = []
call add(lines, '|1,4')
call add(lines, '> ' .. fnamemodify('a.txt', ':p:~'))
call add(lines, "\tb\t7\t0\n")
call writefile(lines, 'Xviminfo')
edit b.txt
call setline(1, range(1, 20))
12mark b
wviminfo Xviminfo
bw!
edit a.txt
rviminfo! Xviminfo
call assert_equal(7, line("'b"))
edit b.txt
rviminfo! Xviminfo
call assert_equal(12, line("'b"))
call delete('Xviminfo')
endfunc
" Test for merging the jump list from a old viminfo file
func Test_viminfo_merge_old_jumplist()
let lines = []
call add(lines, "-' 10 1 " .. fnamemodify('a.txt', ':p:~'))
call add(lines, "-' 20 1 " .. fnamemodify('a.txt', ':p:~'))
call add(lines, "-' 30 1 " .. fnamemodify('b.txt', ':p:~'))
call add(lines, "-' 40 1 " .. fnamemodify('b.txt', ':p:~'))
call writefile(lines, 'Xviminfo')
clearjumps
rviminfo! Xviminfo
let l = getjumplist()[0]
call assert_equal([40, 30, 20, 10], [l[0].lnum, l[1].lnum, l[2].lnum,
\ l[3].lnum])
bw!
call delete('Xviminfo')
endfunc
" vim: shiftwidth=2 sts=2 expandtab
+1 -1
View File
@@ -5570,7 +5570,7 @@ func Test_expr_eval_error_msg()
call T(19, '{(1} + CONT(19)', 'E110', "Missing ')'")
call T(20, '("abc"[1) + CONT(20)', 'E111', "Missing ']'")
call T(21, '(1 +) + CONT(21)', 'E15', "Invalid expression")
call T(22, '1 2 + CONT(22)', 'E15', "Invalid expression")
call T(22, '1 2 + CONT(22)', 'E488', "Trailing characters: 2 +")
call T(23, '(1 ? 2) + CONT(23)', 'E109', "Missing ':' after '?'")
call T(24, '("abc) + CONT(24)', 'E114', "Missing quote")
call T(25, "('abc) + CONT(25)", 'E115', "Missing quote")
+36
View File
@@ -1211,10 +1211,46 @@ f_test_scrollbar(typval_T *argvars, typval_T *rettv UNUSED)
void
f_test_setmouse(typval_T *argvars, typval_T *rettv UNUSED)
{
if (argvars[0].v_type != VAR_NUMBER || (argvars[1].v_type) != VAR_NUMBER)
{
emsg(_(e_invarg));
return;
}
mouse_row = (time_t)tv_get_number(&argvars[0]) - 1;
mouse_col = (time_t)tv_get_number(&argvars[1]) - 1;
}
void
f_test_gui_mouse_event(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
{
#ifdef FEAT_GUI
int button;
int row;
int col;
int repeated_click;
int_u mods;
if (argvars[0].v_type != VAR_NUMBER
|| (argvars[1].v_type) != VAR_NUMBER
|| (argvars[2].v_type) != VAR_NUMBER
|| (argvars[3].v_type) != VAR_NUMBER
|| (argvars[4].v_type) != VAR_NUMBER)
{
emsg(_(e_invarg));
return;
}
button = tv_get_number(&argvars[0]);
row = tv_get_number(&argvars[1]);
col = tv_get_number(&argvars[2]);
repeated_click = tv_get_number(&argvars[3]);
mods = tv_get_number(&argvars[4]);
gui_send_mouse_event(button, TEXT_X(col - 1), TEXT_Y(row - 1), repeated_click, mods);
#endif
}
void
f_test_settime(typval_T *argvars, typval_T *rettv UNUSED)
{
+8 -4
View File
@@ -963,7 +963,9 @@ undo_flush(bufinfo_T *bi)
{
if (bi->bi_buffer != NULL && bi->bi_state != NULL && bi->bi_used > 0)
{
crypt_encode_inplace(bi->bi_state, bi->bi_buffer, bi->bi_used);
// Last parameter is only used for sodium encryption and that
// explicitly disables encryption of undofiles.
crypt_encode_inplace(bi->bi_state, bi->bi_buffer, bi->bi_used, FALSE);
if (fwrite(bi->bi_buffer, bi->bi_used, (size_t)1, bi->bi_fp) != 1)
return FAIL;
bi->bi_used = 0;
@@ -995,7 +997,9 @@ fwrite_crypt(bufinfo_T *bi, char_u *ptr, size_t len)
if (copy == NULL)
return 0;
}
crypt_encode(bi->bi_state, ptr, len, copy);
// Last parameter is only used for sodium encryption and that
// explicitly disables encryption of undofiles.
crypt_encode(bi->bi_state, ptr, len, copy, TRUE);
i = fwrite(copy, len, (size_t)1, bi->bi_fp);
if (copy != small_buf)
vim_free(copy);
@@ -1129,7 +1133,7 @@ undo_read(bufinfo_T *bi, char_u *buffer, size_t size)
}
bi->bi_avail = n;
bi->bi_used = 0;
crypt_decode_inplace(bi->bi_state, bi->bi_buffer, bi->bi_avail);
crypt_decode_inplace(bi->bi_state, bi->bi_buffer, bi->bi_avail, FALSE);
}
n = size_todo;
if (n > bi->bi_avail - bi->bi_used)
@@ -1176,7 +1180,7 @@ read_string_decrypt(bufinfo_T *bi, int len)
ptr[len] = NUL;
#ifdef FEAT_CRYPT
if (bi->bi_state != NULL && bi->bi_buffer == NULL)
crypt_decode_inplace(bi->bi_state, ptr, len);
crypt_decode_inplace(bi->bi_state, ptr, len, FALSE);
#endif
}
return ptr;
+2 -1
View File
@@ -3595,7 +3595,8 @@ trans_function_name(
lead += (int)STRLEN(sid_buf);
}
}
else if (!(flags & TFN_INT) && builtin_function(lv.ll_name, len))
else if (!(flags & TFN_INT) && (builtin_function(lv.ll_name, len)
|| (in_vim9script() && *lv.ll_name == '_')))
{
semsg(_("E128: Function name must start with a capital or \"s:\": %s"),
start);
+61
View File
@@ -563,6 +563,11 @@ static char *(features[]) =
#else
"-smartindent",
#endif
#ifdef FEAT_SODIUM
"+sodium",
#else
"-sodium",
#endif
#ifdef FEAT_SOUND
"+sound",
#else
@@ -765,6 +770,62 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
3036,
/**/
3035,
/**/
3034,
/**/
3033,
/**/
3032,
/**/
3031,
/**/
3030,
/**/
3029,
/**/
3028,
/**/
3027,
/**/
3026,
/**/
3025,
/**/
3024,
/**/
3023,
/**/
3022,
/**/
3021,
/**/
3020,
/**/
3019,
/**/
3018,
/**/
3017,
/**/
3016,
/**/
3015,
/**/
3014,
/**/
3013,
/**/
3012,
/**/
3011,
/**/
3010,
/**/
3009,
/**/
3008,
/**/
+2 -2
View File
@@ -1813,9 +1813,9 @@ typedef enum {
// Keep in sync with INSTRUCTIONS().
#ifdef FEAT_PROFILE
# define COMPILE_TYPE(ufunc) (debug_break_level > 0 ? CT_DEBUG : do_profiling == PROF_YES && (ufunc)->uf_profiling ? CT_PROFILE : CT_NONE)
# define COMPILE_TYPE(ufunc) (debug_break_level > 0 || ufunc->uf_has_breakpoint ? CT_DEBUG : do_profiling == PROF_YES && (ufunc)->uf_profiling ? CT_PROFILE : CT_NONE)
#else
# define COMPILE_TYPE(ufunc) debug_break_level > 0 ? CT_DEBUG : CT_NONE
# define COMPILE_TYPE(ufunc) debug_break_level > 0 || ufunc->uf_has_breakpoint ? CT_DEBUG : CT_NONE
#endif
/*
+8 -1
View File
@@ -209,6 +209,12 @@ typedef struct {
int cuf_argcount; // number of arguments on top of stack
} cufunc_T;
// arguments to ISN_GETITEM
typedef struct {
varnumber_T gi_index;
int gi_with_op;
} getitem_T;
typedef enum {
JUMP_ALWAYS,
JUMP_IF_FALSE, // pop and jump if false
@@ -432,6 +438,7 @@ struct isn_S {
isn_T *instr;
tostring_T tostring;
tobool_T tobool;
getitem_T getitem;
} isn_arg;
};
@@ -498,7 +505,7 @@ extern garray_T def_functions;
// Keep in sync with COMPILE_TYPE()
#ifdef FEAT_PROFILE
# define INSTRUCTIONS(dfunc) \
(debug_break_level > 0 \
(debug_break_level > 0 || dfunc->df_ufunc->uf_has_breakpoint \
? (dfunc)->df_instr_debug \
: ((do_profiling == PROF_YES && (dfunc->df_ufunc)->uf_profiling) \
? (dfunc)->df_instr_prof \
+44 -17
View File
@@ -1240,13 +1240,16 @@ generate_PUSHFUNC(cctx_T *cctx, char_u *name, type_T *type)
/*
* Generate an ISN_GETITEM instruction with "index".
* "with_op" is TRUE for "+=" and other operators, the stack has the current
* value below the list with values.
*/
static int
generate_GETITEM(cctx_T *cctx, int index)
generate_GETITEM(cctx_T *cctx, int index, int with_op)
{
isn_T *isn;
garray_T *stack = &cctx->ctx_type_stack;
type_T *type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
type_T *type = ((type_T **)stack->ga_data)[stack->ga_len
- (with_op ? 2 : 1)];
type_T *item_type = &t_any;
RETURN_OK_IF_SKIP(cctx);
@@ -1260,7 +1263,8 @@ generate_GETITEM(cctx_T *cctx, int index)
item_type = type->tt_member;
if ((isn = generate_instr(cctx, ISN_GETITEM)) == NULL)
return FAIL;
isn->isn_arg.number = index;
isn->isn_arg.getitem.gi_index = index;
isn->isn_arg.getitem.gi_with_op = with_op;
// add the item type to the type stack
if (ga_grow(stack, 1) == FAIL)
@@ -5852,7 +5856,7 @@ get_var_dest(
return FAIL;
}
*dest = dest_reg;
*type = &t_string;
*type = name[1] == '#' ? &t_number_or_string : &t_string;
}
else if (STRNCMP(name, "g:", 2) == 0)
{
@@ -5927,7 +5931,8 @@ generate_store_var(
case dest_env:
return generate_STORE(cctx, ISN_STOREENV, 0, name + 1);
case dest_reg:
return generate_STORE(cctx, ISN_STOREREG, name[1], NULL);
return generate_STORE(cctx, ISN_STOREREG,
name[1] == '@' ? '"' : name[1], NULL);
case dest_vimvar:
return generate_STORE(cctx, ISN_STOREV, vimvaridx, NULL);
case dest_script:
@@ -6745,19 +6750,17 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
int is_const = FALSE;
char_u *wp;
// for "+=", "*=", "..=" etc. first load the current value
if (*op != '='
&& compile_load_lhs_with_index(&lhs, var_start,
cctx) == FAIL)
goto theend;
// For "var = expr" evaluate the expression.
if (var_count == 0)
{
int r;
// for "+=", "*=", "..=" etc. first load the current value
if (*op != '=')
{
if (compile_load_lhs_with_index(&lhs, var_start,
cctx) == FAIL)
goto theend;
}
// Compile the expression.
instr_count = instr->ga_len;
if (incdec)
@@ -6794,7 +6797,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
{
// For "[var, var] = expr" get the "var_idx" item from the
// list.
if (generate_GETITEM(cctx, var_idx) == FAIL)
if (generate_GETITEM(cctx, var_idx, *op != '=') == FAIL)
goto theend;
}
@@ -6843,9 +6846,19 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
goto theend;
}
}
else if (*p != '=' && need_type(rhs_type, lhs.lhs_member_type,
else
{
type_T *lhs_type = lhs.lhs_member_type;
// Special case: assigning to @# can use a number or a
// string.
if (lhs_type == &t_number_or_string
&& rhs_type->tt_type == VAR_NUMBER)
lhs_type = &t_number;
if (*p != '=' && need_type(rhs_type, lhs_type,
-1, 0, cctx, FALSE, FALSE) == FAIL)
goto theend;
}
}
else if (cmdidx == CMD_final)
{
@@ -7711,6 +7724,7 @@ compile_for(char_u *arg_start, cctx_T *cctx)
int semicolon = FALSE;
size_t varlen;
garray_T *stack = &cctx->ctx_type_stack;
garray_T *instr = &cctx->ctx_instr;
scope_T *scope;
lvar_T *loop_lvar; // loop iteration variable
lvar_T *var_lvar; // variable for "var"
@@ -7737,6 +7751,13 @@ compile_for(char_u *arg_start, cctx_T *cctx)
if (may_get_next_line_error(wp, &p, cctx) == FAIL)
return NULL;
// Remove the already generated ISN_DEBUG, it is written below the ISN_FOR
// instruction.
if (cctx->ctx_compile_type == CT_DEBUG && instr->ga_len > 0
&& ((isn_T *)instr->ga_data)[instr->ga_len - 1]
.isn_type == ISN_DEBUG)
--instr->ga_len;
scope = new_scope(cctx, FOR_SCOPE);
if (scope == NULL)
return NULL;
@@ -7788,11 +7809,12 @@ compile_for(char_u *arg_start, cctx_T *cctx)
item_type = vartype->tt_member->tt_member;
}
// CMDMOD_REV must come before the FOR instruction
// CMDMOD_REV must come before the FOR instruction.
generate_undo_cmdmods(cctx);
// "for_end" is set when ":endfor" is found
scope->se_u.se_for.fs_top_label = current_instr_idx(cctx);
generate_FOR(cctx, loop_lvar->lv_idx);
arg = arg_start;
@@ -7893,6 +7915,10 @@ compile_for(char_u *arg_start, cctx_T *cctx)
vim_free(name);
}
if (cctx->ctx_compile_type == CT_DEBUG)
// Add ISN_DEBUG here, so that the loop variables can be inspected.
generate_instr_debug(cctx);
return arg_end;
failed:
@@ -7927,7 +7953,7 @@ compile_endfor(char_u *arg, cctx_T *cctx)
// At end of ":for" scope jump back to the FOR instruction.
generate_JUMP(cctx, JUMP_ALWAYS, forscope->fs_top_label);
// Fill in the "end" label in the FOR statement so it can jump here
// Fill in the "end" label in the FOR statement so it can jump here.
isn = ((isn_T *)instr->ga_data) + forscope->fs_top_label;
isn->isn_arg.forloop.for_end = instr->ga_len;
@@ -8234,6 +8260,7 @@ compile_catch(char_u *arg, cctx_T *cctx UNUSED)
#ifdef FEAT_PROFILE
// the profile-start should be after the jump
if (cctx->ctx_compile_type == CT_PROFILE
&& instr->ga_len > 0
&& ((isn_T *)instr->ga_data)[instr->ga_len - 1]
.isn_type == ISN_PROF_START)
--instr->ga_len;
+114 -28
View File
@@ -147,6 +147,23 @@ exe_newlist(int count, ectx_T *ectx)
return OK;
}
/*
* If debug_tick changed check if "ufunc" has a breakpoint and update
* "uf_has_breakpoint".
*/
static void
update_has_breakpoint(ufunc_T *ufunc)
{
if (ufunc->uf_debug_tick != debug_tick)
{
linenr_T breakpoint;
ufunc->uf_debug_tick = debug_tick;
breakpoint = dbg_find_breakpoint(FALSE, ufunc->uf_name, 0);
ufunc->uf_has_breakpoint = breakpoint > 0;
}
}
/*
* Call compiled function "cdf_idx" from compiled code.
* This adds a stack frame and sets the instruction pointer to the start of the
@@ -212,6 +229,9 @@ call_dfunc(
}
#endif
// Update uf_has_breakpoint if needed.
update_has_breakpoint(ufunc);
// When debugging and using "cont" switches to the not-debugged
// instructions, may need to still compile them.
if ((func_needs_compiling(ufunc, COMPILE_TYPE(ufunc))
@@ -1394,7 +1414,7 @@ typedef struct subs_expr_S {
// Set when calling do_debug().
static ectx_T *debug_context = NULL;
static int debug_arg_count;
static int debug_var_count;
/*
* When debugging lookup "name" and return the typeval.
@@ -1405,23 +1425,100 @@ lookup_debug_var(char_u *name)
{
int idx;
dfunc_T *dfunc;
ufunc_T *ufunc;
ectx_T *ectx = debug_context;
int varargs_off;
if (ectx == NULL)
return NULL;
dfunc = ((dfunc_T *)def_functions.ga_data) + ectx->ec_dfunc_idx;
// Go through the local variable names, from last to first.
for (idx = debug_arg_count - 1; idx >= 0; --idx)
for (idx = debug_var_count - 1; idx >= 0; --idx)
{
char_u *s = ((char_u **)dfunc->df_var_names.ga_data)[idx];
if (STRCMP(s, name) == 0)
if (STRCMP(((char_u **)dfunc->df_var_names.ga_data)[idx], name) == 0)
return STACK_TV_VAR(idx);
}
// Go through argument names.
ufunc = dfunc->df_ufunc;
varargs_off = ufunc->uf_va_name == NULL ? 0 : 1;
for (idx = 0; idx < ufunc->uf_args.ga_len; ++idx)
if (STRCMP(((char_u **)(ufunc->uf_args.ga_data))[idx], name) == 0)
return STACK_TV(ectx->ec_frame_idx - ufunc->uf_args.ga_len
- varargs_off + idx);
if (ufunc->uf_va_name != NULL && STRCMP(ufunc->uf_va_name, name) == 0)
return STACK_TV(ectx->ec_frame_idx - 1);
return NULL;
}
static void
handle_debug(isn_T *iptr, ectx_T *ectx)
{
char_u *line;
ufunc_T *ufunc = (((dfunc_T *)def_functions.ga_data)
+ ectx->ec_dfunc_idx)->df_ufunc;
isn_T *ni;
int end_lnum = iptr->isn_lnum;
garray_T ga;
int lnum;
if (ex_nesting_level > debug_break_level)
{
linenr_T breakpoint;
if (!ufunc->uf_has_breakpoint)
return;
// check for the next breakpoint if needed
breakpoint = dbg_find_breakpoint(FALSE, ufunc->uf_name,
iptr->isn_lnum - 1);
if (breakpoint <= 0 || breakpoint > iptr->isn_lnum)
return;
}
SOURCING_LNUM = iptr->isn_lnum;
debug_context = ectx;
debug_var_count = iptr->isn_arg.number;
for (ni = iptr + 1; ni->isn_type != ISN_FINISH; ++ni)
if (ni->isn_type == ISN_DEBUG
|| ni->isn_type == ISN_RETURN
|| ni->isn_type == ISN_RETURN_VOID)
{
end_lnum = ni->isn_lnum;
break;
}
if (end_lnum > iptr->isn_lnum)
{
ga_init2(&ga, sizeof(char_u *), 10);
for (lnum = iptr->isn_lnum; lnum < end_lnum; ++lnum)
{
char_u *p = skipwhite(
((char_u **)ufunc->uf_lines.ga_data)[lnum - 1]);
if (*p == '#')
break;
if (ga_grow(&ga, 1) == OK)
((char_u **)(ga.ga_data))[ga.ga_len++] = p;
if (STRNCMP(p, "def ", 4) == 0)
break;
}
line = ga_concat_strings(&ga, " ");
vim_free(ga.ga_data);
}
else
line = ((char_u **)ufunc->uf_lines.ga_data)[iptr->isn_lnum - 1];
do_debug(line == NULL ? (char_u *)"[empty]" : line);
debug_context = NULL;
if (end_lnum > iptr->isn_lnum)
vim_free(line);
}
/*
* Execute instructions in execution context "ectx".
* Return OK or FAIL;
@@ -2127,8 +2224,7 @@ exec_instructions(ectx_T *ectx)
--ectx->ec_stack.ga_len;
tv = STACK_TV_BOT(0);
write_reg_contents(reg == '@' ? '"' : reg,
tv_get_string(tv), -1, FALSE);
write_reg_contents(reg, tv_get_string(tv), -1, FALSE);
clear_tv(tv);
}
break;
@@ -3736,12 +3832,12 @@ exec_instructions(ectx_T *ectx)
case ISN_GETITEM:
{
listitem_T *li;
int index = iptr->isn_arg.number;
getitem_T *gi = &iptr->isn_arg.getitem;
// Get list item: list is at stack-1, push item.
// List type and length is checked for when compiling.
tv = STACK_TV_BOT(-1);
li = list_find(tv->vval.v_list, index);
tv = STACK_TV_BOT(-1 - gi->gi_with_op);
li = list_find(tv->vval.v_list, gi->gi_index);
if (GA_GROW(&ectx->ec_stack, 1) == FAIL)
goto theend;
@@ -3750,7 +3846,7 @@ exec_instructions(ectx_T *ectx)
// Useful when used in unpack assignment. Reset at
// ISN_DROP.
ectx->ec_where.wt_index = index + 1;
ectx->ec_where.wt_index = gi->gi_index + 1;
ectx->ec_where.wt_variable = TRUE;
}
break;
@@ -4144,22 +4240,7 @@ exec_instructions(ectx_T *ectx)
break;
case ISN_DEBUG:
if (ex_nesting_level <= debug_break_level)
{
char_u *line;
ufunc_T *ufunc = (((dfunc_T *)def_functions.ga_data)
+ ectx->ec_dfunc_idx)->df_ufunc;
SOURCING_LNUM = iptr->isn_lnum;
debug_context = ectx;
debug_arg_count = iptr->isn_arg.number;
line = ((char_u **)ufunc->uf_lines.ga_data)[
iptr->isn_lnum - 1];
if (line == NULL)
line = (char_u *)"[empty]";
do_debug(line);
debug_context = NULL;
}
handle_debug(iptr, ectx);
break;
case ISN_SHUFFLE:
@@ -4335,6 +4416,9 @@ call_def_function(
#undef STACK_TV_VAR
#define STACK_TV_VAR(idx) (((typval_T *)ectx.ec_stack.ga_data) + ectx.ec_frame_idx + STACK_FRAME_SIZE + idx)
// Update uf_has_breakpoint if needed.
update_has_breakpoint(ufunc);
if (ufunc->uf_def_status == UF_NOT_COMPILED
|| ufunc->uf_def_status == UF_COMPILE_ERROR
|| (func_needs_compiling(ufunc, COMPILE_TYPE(ufunc))
@@ -5292,8 +5376,10 @@ list_instructions(char *pfx, isn_T *instr, int instr_count, ufunc_T *ufunc)
case ISN_ANYSLICE: smsg("%s%4d ANYSLICE", pfx, current); break;
case ISN_SLICE: smsg("%s%4d SLICE %lld",
pfx, current, iptr->isn_arg.number); break;
case ISN_GETITEM: smsg("%s%4d ITEM %lld",
pfx, current, iptr->isn_arg.number); break;
case ISN_GETITEM: smsg("%s%4d ITEM %lld%s", pfx, current,
iptr->isn_arg.getitem.gi_index,
iptr->isn_arg.getitem.gi_with_op ?
" with op" : ""); break;
case ISN_MEMBER: smsg("%s%4d MEMBER", pfx, current); break;
case ISN_STRINGMEMBER: smsg("%s%4d MEMBER %s", pfx, current,
iptr->isn_arg.string); break;
+2 -2
View File
@@ -171,7 +171,7 @@ alloc_func_type(type_T *ret_type, int argcount, garray_T *type_gap)
if (type == NULL)
return &t_any;
type->tt_type = VAR_FUNC;
type->tt_member = ret_type;
type->tt_member = ret_type == NULL ? &t_unknown : ret_type;
type->tt_argcount = argcount;
type->tt_args = NULL;
return type;
@@ -188,7 +188,7 @@ get_func_type(type_T *ret_type, int argcount, garray_T *type_gap)
// recognize commonly used types
if (argcount <= 0)
{
if (ret_type == &t_unknown)
if (ret_type == &t_unknown || ret_type == NULL)
{
// (argcount == 0) is not possible
return &t_func_unknown;