mirror of
https://github.com/macvim-dev/macvim.git
synced 2026-06-11 15:37:29 +02:00
Merge remote-tracking branch 'vim/master'
This commit is contained in:
+4
-2
@@ -2106,8 +2106,8 @@ test1 \
|
||||
test50 test51 test52 test53 test54 test55 test56 test57 test59 \
|
||||
test60 test64 test66 test67 test68 test69 \
|
||||
test70 test72 test73 test74 test75 test77 test78 test79 \
|
||||
test80 test82 test83 test84 test85 test86 test87 test88 \
|
||||
test90 test91 test94 test95 test97 test98 test99 \
|
||||
test80 test83 test84 test85 test86 test87 test88 \
|
||||
test91 test94 test95 test97 test98 test99 \
|
||||
test100 test101 test103 test104 test107 test108:
|
||||
cd testdir; rm -f $@.out; $(MAKE) -f Makefile $@.out VIMPROG=../$(VIMTARGET) $(GUI_TESTARG) SCRIPTSOURCE=../$(SCRIPTSOURCE)
|
||||
|
||||
@@ -2224,6 +2224,7 @@ test_arglist \
|
||||
test_search \
|
||||
test_searchpos \
|
||||
test_set \
|
||||
test_sha256 \
|
||||
test_signs \
|
||||
test_smartindent \
|
||||
test_sort \
|
||||
@@ -2250,6 +2251,7 @@ test_arglist \
|
||||
test_unlet \
|
||||
test_usercommands \
|
||||
test_utf8 \
|
||||
test_utf8_comparisons \
|
||||
test_viminfo \
|
||||
test_vimscript \
|
||||
test_visual \
|
||||
|
||||
+42
-18
@@ -3358,19 +3358,6 @@ source_callback(char_u *fname, void *cookie UNUSED)
|
||||
(void)do_source(fname, FALSE, DOSO_NONE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Source the file "name" from all directories in 'runtimepath'.
|
||||
* "name" can contain wildcards.
|
||||
* When "flags" has DIP_ALL: source all files, otherwise only the first one.
|
||||
*
|
||||
* return FAIL when no file could be sourced, OK otherwise.
|
||||
*/
|
||||
int
|
||||
source_runtime(char_u *name, int flags)
|
||||
{
|
||||
return do_in_runtimepath(name, flags, source_callback, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the file "name" in all directories in "path" and invoke
|
||||
* "callback(fname, cookie)".
|
||||
@@ -3508,18 +3495,19 @@ do_in_path(
|
||||
}
|
||||
|
||||
/*
|
||||
* Find "name" in 'runtimepath'. When found, invoke the callback function for
|
||||
* Find "name" in "path". When found, invoke the callback function for
|
||||
* it: callback(fname, "cookie")
|
||||
* When "flags" has DIP_ALL repeat for all matches, otherwise only the first
|
||||
* one is used.
|
||||
* Returns OK when at least one match found, FAIL otherwise.
|
||||
*
|
||||
* If "name" is NULL calls callback for each entry in runtimepath. Cookie is
|
||||
* If "name" is NULL calls callback for each entry in "path". Cookie is
|
||||
* passed by reference in this case, setting it to NULL indicates that callback
|
||||
* has done its job.
|
||||
*/
|
||||
int
|
||||
do_in_runtimepath(
|
||||
static int
|
||||
do_in_path_and_pp(
|
||||
char_u *path,
|
||||
char_u *name,
|
||||
int flags,
|
||||
void (*callback)(char_u *fname, void *ck),
|
||||
@@ -3532,7 +3520,7 @@ do_in_runtimepath(
|
||||
char *opt_dir = "pack/*/opt/*/%s";
|
||||
|
||||
if ((flags & DIP_NORTP) == 0)
|
||||
done = do_in_path(p_rtp, name, flags, callback, cookie);
|
||||
done = do_in_path(path, name, flags, callback, cookie);
|
||||
|
||||
if ((done == FAIL || (flags & DIP_ALL)) && (flags & DIP_START))
|
||||
{
|
||||
@@ -3559,6 +3547,42 @@ do_in_runtimepath(
|
||||
return done;
|
||||
}
|
||||
|
||||
/*
|
||||
* Just like do_in_path_and_pp(), using 'runtimepath' for "path".
|
||||
*/
|
||||
int
|
||||
do_in_runtimepath(
|
||||
char_u *name,
|
||||
int flags,
|
||||
void (*callback)(char_u *fname, void *ck),
|
||||
void *cookie)
|
||||
{
|
||||
return do_in_path_and_pp(p_rtp, name, flags, callback, cookie);
|
||||
}
|
||||
|
||||
/*
|
||||
* Source the file "name" from all directories in 'runtimepath'.
|
||||
* "name" can contain wildcards.
|
||||
* When "flags" has DIP_ALL: source all files, otherwise only the first one.
|
||||
*
|
||||
* return FAIL when no file could be sourced, OK otherwise.
|
||||
*/
|
||||
int
|
||||
source_runtime(char_u *name, int flags)
|
||||
{
|
||||
return source_in_path(p_rtp, name, flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* Just like source_runtime(), but use "path" instead of 'runtimepath'.
|
||||
*/
|
||||
int
|
||||
source_in_path(char_u *path, char_u *name, int flags)
|
||||
{
|
||||
return do_in_path_and_pp(path, name, flags, source_callback, NULL);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Expand wildcards in "pat" and invoke do_source() for each match.
|
||||
*/
|
||||
|
||||
+417
-354
@@ -3166,6 +3166,7 @@ buf_write(
|
||||
int device = FALSE; /* writing to a device */
|
||||
stat_T st_old;
|
||||
int prev_got_int = got_int;
|
||||
int checking_conversion;
|
||||
int file_readonly = FALSE; /* overwritten file is read-only */
|
||||
static char *err_readonly = "is read-only (cannot override: \"W\" in 'cpoptions')";
|
||||
#if defined(UNIX) /*XXX fix me sometime? */
|
||||
@@ -4344,433 +4345,491 @@ buf_write(
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Open the file "wfname" for writing.
|
||||
* We may try to open the file twice: If we can't write to the
|
||||
* file and forceit is TRUE we delete the existing file and try to create
|
||||
* a new one. If this still fails we may have lost the original file!
|
||||
* (this may happen when the user reached his quotum for number of files).
|
||||
* Appending will fail if the file does not exist and forceit is FALSE.
|
||||
* If conversion is taking place, we may first pretend to write and check
|
||||
* for conversion errors. Then loop again to write for real.
|
||||
* When not doing conversion this writes for real right away.
|
||||
*/
|
||||
while ((fd = mch_open((char *)wfname, O_WRONLY | O_EXTRA | (append
|
||||
? (forceit ? (O_APPEND | O_CREAT) : O_APPEND)
|
||||
: (O_CREAT | O_TRUNC))
|
||||
, perm < 0 ? 0666 : (perm & 0777))) < 0)
|
||||
for (checking_conversion = TRUE; ; checking_conversion = FALSE)
|
||||
{
|
||||
/*
|
||||
* A forced write will try to create a new file if the old one is
|
||||
* still readonly. This may also happen when the directory is
|
||||
* read-only. In that case the mch_remove() will fail.
|
||||
* There is no need to check conversion when:
|
||||
* - there is no conversion
|
||||
* - we make a backup file, that can be restored in case of conversion
|
||||
* failure.
|
||||
*/
|
||||
if (errmsg == NULL)
|
||||
{
|
||||
#ifdef UNIX
|
||||
stat_T st;
|
||||
|
||||
/* Don't delete the file when it's a hard or symbolic link. */
|
||||
if ((!newfile && st_old.st_nlink > 1)
|
||||
|| (mch_lstat((char *)fname, &st) == 0
|
||||
&& (st.st_dev != st_old.st_dev
|
||||
|| st.st_ino != st_old.st_ino)))
|
||||
errmsg = (char_u *)_("E166: Can't open linked file for writing");
|
||||
else
|
||||
#ifdef FEAT_MBYTE
|
||||
if (!converted || dobackup)
|
||||
#endif
|
||||
checking_conversion = FALSE;
|
||||
|
||||
if (checking_conversion)
|
||||
{
|
||||
/* Make sure we don't write anything. */
|
||||
fd = -1;
|
||||
write_info.bw_fd = fd;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* Open the file "wfname" for writing.
|
||||
* We may try to open the file twice: If we can't write to the file
|
||||
* and forceit is TRUE we delete the existing file and try to
|
||||
* create a new one. If this still fails we may have lost the
|
||||
* original file! (this may happen when the user reached his
|
||||
* quotum for number of files).
|
||||
* Appending will fail if the file does not exist and forceit is
|
||||
* FALSE.
|
||||
*/
|
||||
while ((fd = mch_open((char *)wfname, O_WRONLY | O_EXTRA | (append
|
||||
? (forceit ? (O_APPEND | O_CREAT) : O_APPEND)
|
||||
: (O_CREAT | O_TRUNC))
|
||||
, perm < 0 ? 0666 : (perm & 0777))) < 0)
|
||||
{
|
||||
errmsg = (char_u *)_("E212: Can't open file for writing");
|
||||
if (forceit && vim_strchr(p_cpo, CPO_FWRITE) == NULL
|
||||
&& perm >= 0)
|
||||
/*
|
||||
* A forced write will try to create a new file if the old one
|
||||
* is still readonly. This may also happen when the directory
|
||||
* is read-only. In that case the mch_remove() will fail.
|
||||
*/
|
||||
if (errmsg == NULL)
|
||||
{
|
||||
#ifdef UNIX
|
||||
/* we write to the file, thus it should be marked
|
||||
writable after all */
|
||||
if (!(perm & 0200))
|
||||
made_writable = TRUE;
|
||||
perm |= 0200;
|
||||
if (st_old.st_uid != getuid() || st_old.st_gid != getgid())
|
||||
perm &= 0777;
|
||||
stat_T st;
|
||||
|
||||
/* Don't delete the file when it's a hard or symbolic link.
|
||||
*/
|
||||
if ((!newfile && st_old.st_nlink > 1)
|
||||
|| (mch_lstat((char *)fname, &st) == 0
|
||||
&& (st.st_dev != st_old.st_dev
|
||||
|| st.st_ino != st_old.st_ino)))
|
||||
errmsg = (char_u *)_("E166: Can't open linked file for writing");
|
||||
else
|
||||
#endif
|
||||
if (!append) /* don't remove when appending */
|
||||
mch_remove(wfname);
|
||||
continue;
|
||||
{
|
||||
errmsg = (char_u *)_("E212: Can't open file for writing");
|
||||
if (forceit && vim_strchr(p_cpo, CPO_FWRITE) == NULL
|
||||
&& perm >= 0)
|
||||
{
|
||||
#ifdef UNIX
|
||||
/* we write to the file, thus it should be marked
|
||||
writable after all */
|
||||
if (!(perm & 0200))
|
||||
made_writable = TRUE;
|
||||
perm |= 0200;
|
||||
if (st_old.st_uid != getuid()
|
||||
|| st_old.st_gid != getgid())
|
||||
perm &= 0777;
|
||||
#endif
|
||||
if (!append) /* don't remove when appending */
|
||||
mch_remove(wfname);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
restore_backup:
|
||||
{
|
||||
stat_T st;
|
||||
|
||||
/*
|
||||
* If we failed to open the file, we don't need a backup. Throw it
|
||||
* away. If we moved or removed the original file try to put the
|
||||
* backup in its place.
|
||||
*/
|
||||
if (backup != NULL && wfname == fname)
|
||||
{
|
||||
if (backup_copy)
|
||||
{
|
||||
stat_T st;
|
||||
|
||||
/*
|
||||
* There is a small chance that we removed the original,
|
||||
* try to move the copy in its place.
|
||||
* This may not work if the vim_rename() fails.
|
||||
* In that case we leave the copy around.
|
||||
* If we failed to open the file, we don't need a backup.
|
||||
* Throw it away. If we moved or removed the original file
|
||||
* try to put the backup in its place.
|
||||
*/
|
||||
/* If file does not exist, put the copy in its place */
|
||||
if (mch_stat((char *)fname, &st) < 0)
|
||||
vim_rename(backup, fname);
|
||||
/* if original file does exist throw away the copy */
|
||||
if (mch_stat((char *)fname, &st) >= 0)
|
||||
mch_remove(backup);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* try to put the original file back */
|
||||
vim_rename(backup, fname);
|
||||
}
|
||||
}
|
||||
if (backup != NULL && wfname == fname)
|
||||
{
|
||||
if (backup_copy)
|
||||
{
|
||||
/*
|
||||
* There is a small chance that we removed the
|
||||
* original, try to move the copy in its place.
|
||||
* This may not work if the vim_rename() fails.
|
||||
* In that case we leave the copy around.
|
||||
*/
|
||||
/* If file does not exist, put the copy in its
|
||||
* place */
|
||||
if (mch_stat((char *)fname, &st) < 0)
|
||||
vim_rename(backup, fname);
|
||||
/* if original file does exist throw away the copy
|
||||
*/
|
||||
if (mch_stat((char *)fname, &st) >= 0)
|
||||
mch_remove(backup);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* try to put the original file back */
|
||||
vim_rename(backup, fname);
|
||||
}
|
||||
}
|
||||
|
||||
/* if original file no longer exists give an extra warning */
|
||||
if (!newfile && mch_stat((char *)fname, &st) < 0)
|
||||
end = 0;
|
||||
}
|
||||
/* if original file no longer exists give an extra warning
|
||||
*/
|
||||
if (!newfile && mch_stat((char *)fname, &st) < 0)
|
||||
end = 0;
|
||||
}
|
||||
|
||||
#ifdef FEAT_MBYTE
|
||||
if (wfname != fname)
|
||||
vim_free(wfname);
|
||||
if (wfname != fname)
|
||||
vim_free(wfname);
|
||||
#endif
|
||||
goto fail;
|
||||
}
|
||||
errmsg = NULL;
|
||||
goto fail;
|
||||
}
|
||||
write_info.bw_fd = fd;
|
||||
|
||||
#if defined(MACOS_CLASSIC) || defined(WIN3264)
|
||||
/* TODO: Is it need for MACOS_X? (Dany) */
|
||||
/*
|
||||
* On macintosh copy the original files attributes (i.e. the backup)
|
||||
* This is done in order to preserve the resource fork and the
|
||||
* Finder attribute (label, comments, custom icons, file creator)
|
||||
*/
|
||||
if (backup != NULL && overwriting && !append)
|
||||
{
|
||||
if (backup_copy)
|
||||
(void)mch_copy_file_attribute(wfname, backup);
|
||||
else
|
||||
(void)mch_copy_file_attribute(backup, wfname);
|
||||
}
|
||||
/* TODO: Is it need for MACOS_X? (Dany) */
|
||||
/*
|
||||
* On macintosh copy the original files attributes (i.e. the backup)
|
||||
* This is done in order to preserve the resource fork and the
|
||||
* Finder attribute (label, comments, custom icons, file creator)
|
||||
*/
|
||||
if (backup != NULL && overwriting && !append)
|
||||
{
|
||||
if (backup_copy)
|
||||
(void)mch_copy_file_attribute(wfname, backup);
|
||||
else
|
||||
(void)mch_copy_file_attribute(backup, wfname);
|
||||
}
|
||||
|
||||
if (!overwriting && !append)
|
||||
{
|
||||
if (buf->b_ffname != NULL)
|
||||
(void)mch_copy_file_attribute(buf->b_ffname, wfname);
|
||||
/* Should copy resource fork */
|
||||
}
|
||||
if (!overwriting && !append)
|
||||
{
|
||||
if (buf->b_ffname != NULL)
|
||||
(void)mch_copy_file_attribute(buf->b_ffname, wfname);
|
||||
/* Should copy resource fork */
|
||||
}
|
||||
#endif
|
||||
|
||||
write_info.bw_fd = fd;
|
||||
|
||||
#ifdef FEAT_CRYPT
|
||||
if (*buf->b_p_key != NUL && !filtering)
|
||||
{
|
||||
char_u *header;
|
||||
int header_len;
|
||||
|
||||
buf->b_cryptstate = crypt_create_for_writing(crypt_get_method_nr(buf),
|
||||
buf->b_p_key, &header, &header_len);
|
||||
if (buf->b_cryptstate == NULL || header == NULL)
|
||||
end = 0;
|
||||
else
|
||||
{
|
||||
/* Write magic number, so that Vim knows how this file is
|
||||
* encrypted when reading it back. */
|
||||
write_info.bw_buf = header;
|
||||
write_info.bw_len = header_len;
|
||||
write_info.bw_flags = FIO_NOCONVERT;
|
||||
if (buf_write_bytes(&write_info) == FAIL)
|
||||
end = 0;
|
||||
wb_flags |= FIO_ENCRYPTED;
|
||||
vim_free(header);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
write_info.bw_buf = buffer;
|
||||
nchars = 0;
|
||||
|
||||
/* use "++bin", "++nobin" or 'binary' */
|
||||
if (eap != NULL && eap->force_bin != 0)
|
||||
write_bin = (eap->force_bin == FORCE_BIN);
|
||||
else
|
||||
write_bin = buf->b_p_bin;
|
||||
|
||||
#ifdef FEAT_MBYTE
|
||||
/*
|
||||
* The BOM is written just after the encryption magic number.
|
||||
* Skip it when appending and the file already existed, the BOM only makes
|
||||
* sense at the start of the file.
|
||||
*/
|
||||
if (buf->b_p_bomb && !write_bin && (!append || perm < 0))
|
||||
{
|
||||
write_info.bw_len = make_bom(buffer, fenc);
|
||||
if (write_info.bw_len > 0)
|
||||
{
|
||||
/* don't convert, do encryption */
|
||||
write_info.bw_flags = FIO_NOCONVERT | wb_flags;
|
||||
if (buf_write_bytes(&write_info) == FAIL)
|
||||
end = 0;
|
||||
else
|
||||
nchars += write_info.bw_len;
|
||||
}
|
||||
}
|
||||
write_info.bw_start_lnum = start;
|
||||
#endif
|
||||
|
||||
#ifdef FEAT_PERSISTENT_UNDO
|
||||
write_undo_file = (buf->b_p_udf && overwriting && !append
|
||||
&& !filtering && reset_changed);
|
||||
if (write_undo_file)
|
||||
/* Prepare for computing the hash value of the text. */
|
||||
sha256_start(&sha_ctx);
|
||||
#endif
|
||||
|
||||
write_info.bw_len = bufsize;
|
||||
#ifdef HAS_BW_FLAGS
|
||||
write_info.bw_flags = wb_flags;
|
||||
#endif
|
||||
fileformat = get_fileformat_force(buf, eap);
|
||||
s = buffer;
|
||||
len = 0;
|
||||
for (lnum = start; lnum <= end; ++lnum)
|
||||
{
|
||||
/*
|
||||
* The next while loop is done once for each character written.
|
||||
* Keep it fast!
|
||||
*/
|
||||
ptr = ml_get_buf(buf, lnum, FALSE) - 1;
|
||||
#ifdef FEAT_PERSISTENT_UNDO
|
||||
if (write_undo_file)
|
||||
sha256_update(&sha_ctx, ptr + 1, (UINT32_T)(STRLEN(ptr + 1) + 1));
|
||||
#endif
|
||||
while ((c = *++ptr) != NUL)
|
||||
{
|
||||
if (c == NL)
|
||||
*s = NUL; /* replace newlines with NULs */
|
||||
else if (c == CAR && fileformat == EOL_MAC)
|
||||
*s = NL; /* Mac: replace CRs with NLs */
|
||||
else
|
||||
*s = c;
|
||||
++s;
|
||||
if (++len != bufsize)
|
||||
continue;
|
||||
if (buf_write_bytes(&write_info) == FAIL)
|
||||
if (*buf->b_p_key != NUL && !filtering)
|
||||
{
|
||||
end = 0; /* write error: break loop */
|
||||
break;
|
||||
}
|
||||
nchars += bufsize;
|
||||
s = buffer;
|
||||
len = 0;
|
||||
#ifdef FEAT_MBYTE
|
||||
write_info.bw_start_lnum = lnum;
|
||||
#endif
|
||||
}
|
||||
/* write failed or last line has no EOL: stop here */
|
||||
if (end == 0
|
||||
|| (lnum == end
|
||||
&& (write_bin || !buf->b_p_fixeol)
|
||||
&& (lnum == buf->b_no_eol_lnum
|
||||
|| (lnum == buf->b_ml.ml_line_count && !buf->b_p_eol))))
|
||||
{
|
||||
++lnum; /* written the line, count it */
|
||||
no_eol = TRUE;
|
||||
break;
|
||||
}
|
||||
if (fileformat == EOL_UNIX)
|
||||
*s++ = NL;
|
||||
else
|
||||
{
|
||||
*s++ = CAR; /* EOL_MAC or EOL_DOS: write CR */
|
||||
if (fileformat == EOL_DOS) /* write CR-NL */
|
||||
{
|
||||
if (++len == bufsize)
|
||||
char_u *header;
|
||||
int header_len;
|
||||
|
||||
buf->b_cryptstate = crypt_create_for_writing(
|
||||
crypt_get_method_nr(buf),
|
||||
buf->b_p_key, &header, &header_len);
|
||||
if (buf->b_cryptstate == NULL || header == NULL)
|
||||
end = 0;
|
||||
else
|
||||
{
|
||||
/* Write magic number, so that Vim knows how this file is
|
||||
* encrypted when reading it back. */
|
||||
write_info.bw_buf = header;
|
||||
write_info.bw_len = header_len;
|
||||
write_info.bw_flags = FIO_NOCONVERT;
|
||||
if (buf_write_bytes(&write_info) == FAIL)
|
||||
{
|
||||
end = 0; /* write error: break loop */
|
||||
break;
|
||||
}
|
||||
nchars += bufsize;
|
||||
s = buffer;
|
||||
len = 0;
|
||||
end = 0;
|
||||
wb_flags |= FIO_ENCRYPTED;
|
||||
vim_free(header);
|
||||
}
|
||||
*s++ = NL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (++len == bufsize && end)
|
||||
{
|
||||
if (buf_write_bytes(&write_info) == FAIL)
|
||||
{
|
||||
end = 0; /* write error: break loop */
|
||||
break;
|
||||
}
|
||||
nchars += bufsize;
|
||||
s = buffer;
|
||||
len = 0;
|
||||
errmsg = NULL;
|
||||
|
||||
ui_breakcheck();
|
||||
if (got_int)
|
||||
{
|
||||
end = 0; /* Interrupted, break loop */
|
||||
break;
|
||||
}
|
||||
}
|
||||
#ifdef VMS
|
||||
write_info.bw_buf = buffer;
|
||||
nchars = 0;
|
||||
|
||||
/* use "++bin", "++nobin" or 'binary' */
|
||||
if (eap != NULL && eap->force_bin != 0)
|
||||
write_bin = (eap->force_bin == FORCE_BIN);
|
||||
else
|
||||
write_bin = buf->b_p_bin;
|
||||
|
||||
#ifdef FEAT_MBYTE
|
||||
/*
|
||||
* On VMS there is a problem: newlines get added when writing blocks
|
||||
* at a time. Fix it by writing a line at a time.
|
||||
* This is much slower!
|
||||
* Explanation: VAX/DECC RTL insists that records in some RMS
|
||||
* structures end with a newline (carriage return) character, and if
|
||||
* they don't it adds one.
|
||||
* With other RMS structures it works perfect without this fix.
|
||||
* The BOM is written just after the encryption magic number.
|
||||
* Skip it when appending and the file already existed, the BOM only
|
||||
* makes sense at the start of the file.
|
||||
*/
|
||||
if (buf->b_fab_rfm == FAB$C_VFC
|
||||
|| ((buf->b_fab_rat & (FAB$M_FTN | FAB$M_CR)) != 0))
|
||||
if (buf->b_p_bomb && !write_bin && (!append || perm < 0))
|
||||
{
|
||||
int b2write;
|
||||
|
||||
buf->b_fab_mrs = (buf->b_fab_mrs == 0
|
||||
? MIN(4096, bufsize)
|
||||
: MIN(buf->b_fab_mrs, bufsize));
|
||||
|
||||
b2write = len;
|
||||
while (b2write > 0)
|
||||
write_info.bw_len = make_bom(buffer, fenc);
|
||||
if (write_info.bw_len > 0)
|
||||
{
|
||||
write_info.bw_len = MIN(b2write, buf->b_fab_mrs);
|
||||
/* don't convert, do encryption */
|
||||
write_info.bw_flags = FIO_NOCONVERT | wb_flags;
|
||||
if (buf_write_bytes(&write_info) == FAIL)
|
||||
end = 0;
|
||||
else
|
||||
nchars += write_info.bw_len;
|
||||
}
|
||||
}
|
||||
write_info.bw_start_lnum = start;
|
||||
#endif
|
||||
|
||||
#ifdef FEAT_PERSISTENT_UNDO
|
||||
write_undo_file = (buf->b_p_udf
|
||||
&& overwriting
|
||||
&& !append
|
||||
&& !filtering
|
||||
&& reset_changed
|
||||
&& !checking_conversion);
|
||||
if (write_undo_file)
|
||||
/* Prepare for computing the hash value of the text. */
|
||||
sha256_start(&sha_ctx);
|
||||
#endif
|
||||
|
||||
write_info.bw_len = bufsize;
|
||||
#ifdef HAS_BW_FLAGS
|
||||
write_info.bw_flags = wb_flags;
|
||||
#endif
|
||||
fileformat = get_fileformat_force(buf, eap);
|
||||
s = buffer;
|
||||
len = 0;
|
||||
for (lnum = start; lnum <= end; ++lnum)
|
||||
{
|
||||
/*
|
||||
* The next while loop is done once for each character written.
|
||||
* Keep it fast!
|
||||
*/
|
||||
ptr = ml_get_buf(buf, lnum, FALSE) - 1;
|
||||
#ifdef FEAT_PERSISTENT_UNDO
|
||||
if (write_undo_file)
|
||||
sha256_update(&sha_ctx, ptr + 1,
|
||||
(UINT32_T)(STRLEN(ptr + 1) + 1));
|
||||
#endif
|
||||
while ((c = *++ptr) != NUL)
|
||||
{
|
||||
if (c == NL)
|
||||
*s = NUL; /* replace newlines with NULs */
|
||||
else if (c == CAR && fileformat == EOL_MAC)
|
||||
*s = NL; /* Mac: replace CRs with NLs */
|
||||
else
|
||||
*s = c;
|
||||
++s;
|
||||
if (++len != bufsize)
|
||||
continue;
|
||||
if (buf_write_bytes(&write_info) == FAIL)
|
||||
{
|
||||
end = 0;
|
||||
end = 0; /* write error: break loop */
|
||||
break;
|
||||
}
|
||||
b2write -= MIN(b2write, buf->b_fab_mrs);
|
||||
}
|
||||
write_info.bw_len = bufsize;
|
||||
nchars += len;
|
||||
s = buffer;
|
||||
len = 0;
|
||||
}
|
||||
nchars += bufsize;
|
||||
s = buffer;
|
||||
len = 0;
|
||||
#ifdef FEAT_MBYTE
|
||||
write_info.bw_start_lnum = lnum;
|
||||
#endif
|
||||
}
|
||||
if (len > 0 && end > 0)
|
||||
{
|
||||
write_info.bw_len = len;
|
||||
if (buf_write_bytes(&write_info) == FAIL)
|
||||
end = 0; /* write error */
|
||||
nchars += len;
|
||||
}
|
||||
/* write failed or last line has no EOL: stop here */
|
||||
if (end == 0
|
||||
|| (lnum == end
|
||||
&& (write_bin || !buf->b_p_fixeol)
|
||||
&& (lnum == buf->b_no_eol_lnum
|
||||
|| (lnum == buf->b_ml.ml_line_count
|
||||
&& !buf->b_p_eol))))
|
||||
{
|
||||
++lnum; /* written the line, count it */
|
||||
no_eol = TRUE;
|
||||
break;
|
||||
}
|
||||
if (fileformat == EOL_UNIX)
|
||||
*s++ = NL;
|
||||
else
|
||||
{
|
||||
*s++ = CAR; /* EOL_MAC or EOL_DOS: write CR */
|
||||
if (fileformat == EOL_DOS) /* write CR-NL */
|
||||
{
|
||||
if (++len == bufsize)
|
||||
{
|
||||
if (buf_write_bytes(&write_info) == FAIL)
|
||||
{
|
||||
end = 0; /* write error: break loop */
|
||||
break;
|
||||
}
|
||||
nchars += bufsize;
|
||||
s = buffer;
|
||||
len = 0;
|
||||
}
|
||||
*s++ = NL;
|
||||
}
|
||||
}
|
||||
if (++len == bufsize && end)
|
||||
{
|
||||
if (buf_write_bytes(&write_info) == FAIL)
|
||||
{
|
||||
end = 0; /* write error: break loop */
|
||||
break;
|
||||
}
|
||||
nchars += bufsize;
|
||||
s = buffer;
|
||||
len = 0;
|
||||
|
||||
ui_breakcheck();
|
||||
if (got_int)
|
||||
{
|
||||
end = 0; /* Interrupted, break loop */
|
||||
break;
|
||||
}
|
||||
}
|
||||
#ifdef VMS
|
||||
/*
|
||||
* On VMS there is a problem: newlines get added when writing
|
||||
* blocks at a time. Fix it by writing a line at a time.
|
||||
* This is much slower!
|
||||
* Explanation: VAX/DECC RTL insists that records in some RMS
|
||||
* structures end with a newline (carriage return) character, and
|
||||
* if they don't it adds one.
|
||||
* With other RMS structures it works perfect without this fix.
|
||||
*/
|
||||
if (buf->b_fab_rfm == FAB$C_VFC
|
||||
|| ((buf->b_fab_rat & (FAB$M_FTN | FAB$M_CR)) != 0))
|
||||
{
|
||||
int b2write;
|
||||
|
||||
buf->b_fab_mrs = (buf->b_fab_mrs == 0
|
||||
? MIN(4096, bufsize)
|
||||
: MIN(buf->b_fab_mrs, bufsize));
|
||||
|
||||
b2write = len;
|
||||
while (b2write > 0)
|
||||
{
|
||||
write_info.bw_len = MIN(b2write, buf->b_fab_mrs);
|
||||
if (buf_write_bytes(&write_info) == FAIL)
|
||||
{
|
||||
end = 0;
|
||||
break;
|
||||
}
|
||||
b2write -= MIN(b2write, buf->b_fab_mrs);
|
||||
}
|
||||
write_info.bw_len = bufsize;
|
||||
nchars += len;
|
||||
s = buffer;
|
||||
len = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (len > 0 && end > 0)
|
||||
{
|
||||
write_info.bw_len = len;
|
||||
if (buf_write_bytes(&write_info) == FAIL)
|
||||
end = 0; /* write error */
|
||||
nchars += len;
|
||||
}
|
||||
|
||||
/* Stop when writing done or an error was encountered. */
|
||||
if (!checking_conversion || end == 0)
|
||||
break;
|
||||
|
||||
/* If no error happened until now, writing should be ok, so loop to
|
||||
* really write the buffer. */
|
||||
}
|
||||
|
||||
#if defined(UNIX) && defined(HAVE_FSYNC)
|
||||
/* On many journalling file systems there is a bug that causes both the
|
||||
* original and the backup file to be lost when halting the system right
|
||||
* after writing the file. That's because only the meta-data is
|
||||
* journalled. Syncing the file slows down the system, but assures it has
|
||||
* been written to disk and we don't lose it.
|
||||
* For a device do try the fsync() but don't complain if it does not work
|
||||
* (could be a pipe).
|
||||
* If the 'fsync' option is FALSE, don't fsync(). Useful for laptops. */
|
||||
if (p_fs && fsync(fd) != 0 && !device)
|
||||
/* If we started writing, finish writing. Also when an error was
|
||||
* encountered. */
|
||||
if (!checking_conversion)
|
||||
{
|
||||
errmsg = (char_u *)_("E667: Fsync failed");
|
||||
end = 0;
|
||||
}
|
||||
#if defined(UNIX) && defined(HAVE_FSYNC)
|
||||
/*
|
||||
* On many journalling file systems there is a bug that causes both the
|
||||
* original and the backup file to be lost when halting the system
|
||||
* right after writing the file. That's because only the meta-data is
|
||||
* journalled. Syncing the file slows down the system, but assures it
|
||||
* has been written to disk and we don't lose it.
|
||||
* For a device do try the fsync() but don't complain if it does not
|
||||
* work (could be a pipe).
|
||||
* If the 'fsync' option is FALSE, don't fsync(). Useful for laptops.
|
||||
*/
|
||||
if (p_fs && fsync(fd) != 0 && !device)
|
||||
{
|
||||
errmsg = (char_u *)_("E667: Fsync failed");
|
||||
end = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_SELINUX) || defined(HAVE_SMACK)
|
||||
/* Probably need to set the security context. */
|
||||
if (!backup_copy)
|
||||
mch_copy_sec(backup, wfname);
|
||||
/* Probably need to set the security context. */
|
||||
if (!backup_copy)
|
||||
mch_copy_sec(backup, wfname);
|
||||
#endif
|
||||
|
||||
#ifdef UNIX
|
||||
/* When creating a new file, set its owner/group to that of the original
|
||||
* file. Get the new device and inode number. */
|
||||
if (backup != NULL && !backup_copy)
|
||||
{
|
||||
# ifdef HAVE_FCHOWN
|
||||
stat_T st;
|
||||
|
||||
/* don't change the owner when it's already OK, some systems remove
|
||||
* permission or ACL stuff */
|
||||
if (mch_stat((char *)wfname, &st) < 0
|
||||
|| st.st_uid != st_old.st_uid
|
||||
|| st.st_gid != st_old.st_gid)
|
||||
/* When creating a new file, set its owner/group to that of the
|
||||
* original file. Get the new device and inode number. */
|
||||
if (backup != NULL && !backup_copy)
|
||||
{
|
||||
ignored = fchown(fd, st_old.st_uid, st_old.st_gid);
|
||||
if (perm >= 0) /* set permission again, may have changed */
|
||||
(void)mch_setperm(wfname, perm);
|
||||
}
|
||||
# ifdef HAVE_FCHOWN
|
||||
stat_T st;
|
||||
|
||||
/* don't change the owner when it's already OK, some systems remove
|
||||
* permission or ACL stuff */
|
||||
if (mch_stat((char *)wfname, &st) < 0
|
||||
|| st.st_uid != st_old.st_uid
|
||||
|| st.st_gid != st_old.st_gid)
|
||||
{
|
||||
ignored = fchown(fd, st_old.st_uid, st_old.st_gid);
|
||||
if (perm >= 0) /* set permission again, may have changed */
|
||||
(void)mch_setperm(wfname, perm);
|
||||
}
|
||||
# endif
|
||||
buf_setino(buf);
|
||||
}
|
||||
else if (!buf->b_dev_valid)
|
||||
/* Set the inode when creating a new file. */
|
||||
buf_setino(buf);
|
||||
buf_setino(buf);
|
||||
}
|
||||
else if (!buf->b_dev_valid)
|
||||
/* Set the inode when creating a new file. */
|
||||
buf_setino(buf);
|
||||
#endif
|
||||
|
||||
if (close(fd) != 0)
|
||||
{
|
||||
errmsg = (char_u *)_("E512: Close failed");
|
||||
end = 0;
|
||||
}
|
||||
if (close(fd) != 0)
|
||||
{
|
||||
errmsg = (char_u *)_("E512: Close failed");
|
||||
end = 0;
|
||||
}
|
||||
|
||||
#ifdef UNIX
|
||||
if (made_writable)
|
||||
perm &= ~0200; /* reset 'w' bit for security reasons */
|
||||
if (made_writable)
|
||||
perm &= ~0200; /* reset 'w' bit for security reasons */
|
||||
#endif
|
||||
if (perm >= 0) /* set perm. of new file same as old file */
|
||||
(void)mch_setperm(wfname, perm);
|
||||
if (perm >= 0) /* set perm. of new file same as old file */
|
||||
(void)mch_setperm(wfname, perm);
|
||||
#ifdef HAVE_ACL
|
||||
/*
|
||||
* Probably need to set the ACL before changing the user (can't set the
|
||||
* ACL on a file the user doesn't own).
|
||||
* On Solaris, with ZFS and the aclmode property set to "discard" (the
|
||||
* default), chmod() discards all part of a file's ACL that don't represent
|
||||
* the mode of the file. It's non-trivial for us to discover whether we're
|
||||
* in that situation, so we simply always re-set the ACL.
|
||||
*/
|
||||
/*
|
||||
* Probably need to set the ACL before changing the user (can't set the
|
||||
* ACL on a file the user doesn't own).
|
||||
* On Solaris, with ZFS and the aclmode property set to "discard" (the
|
||||
* default), chmod() discards all part of a file's ACL that don't
|
||||
* represent the mode of the file. It's non-trivial for us to discover
|
||||
* whether we're in that situation, so we simply always re-set the ACL.
|
||||
*/
|
||||
# ifndef HAVE_SOLARIS_ZFS_ACL
|
||||
if (!backup_copy)
|
||||
if (!backup_copy)
|
||||
# endif
|
||||
mch_set_acl(wfname, acl);
|
||||
mch_set_acl(wfname, acl);
|
||||
#endif
|
||||
#ifdef FEAT_CRYPT
|
||||
if (buf->b_cryptstate != NULL)
|
||||
{
|
||||
crypt_free_state(buf->b_cryptstate);
|
||||
buf->b_cryptstate = NULL;
|
||||
}
|
||||
if (buf->b_cryptstate != NULL)
|
||||
{
|
||||
crypt_free_state(buf->b_cryptstate);
|
||||
buf->b_cryptstate = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(FEAT_MBYTE) && defined(FEAT_EVAL)
|
||||
if (wfname != fname)
|
||||
{
|
||||
/*
|
||||
* The file was written to a temp file, now it needs to be converted
|
||||
* with 'charconvert' to (overwrite) the output file.
|
||||
*/
|
||||
if (end != 0)
|
||||
if (wfname != fname)
|
||||
{
|
||||
if (eval_charconvert(enc_utf8 ? (char_u *)"utf-8" : p_enc, fenc,
|
||||
wfname, fname) == FAIL)
|
||||
/*
|
||||
* The file was written to a temp file, now it needs to be
|
||||
* converted with 'charconvert' to (overwrite) the output file.
|
||||
*/
|
||||
if (end != 0)
|
||||
{
|
||||
write_info.bw_conv_error = TRUE;
|
||||
end = 0;
|
||||
if (eval_charconvert(enc_utf8 ? (char_u *)"utf-8" : p_enc,
|
||||
fenc, wfname, fname) == FAIL)
|
||||
{
|
||||
write_info.bw_conv_error = TRUE;
|
||||
end = 0;
|
||||
}
|
||||
}
|
||||
mch_remove(wfname);
|
||||
vim_free(wfname);
|
||||
}
|
||||
mch_remove(wfname);
|
||||
vim_free(wfname);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (end == 0)
|
||||
{
|
||||
/*
|
||||
* Error encountered.
|
||||
*/
|
||||
if (errmsg == NULL)
|
||||
{
|
||||
#ifdef FEAT_MBYTE
|
||||
@@ -5694,6 +5753,10 @@ buf_write_bytes(struct bw_info *ip)
|
||||
}
|
||||
#endif /* FEAT_MBYTE */
|
||||
|
||||
if (ip->bw_fd < 0)
|
||||
/* Only checking conversion, which is OK if we get here. */
|
||||
return OK;
|
||||
|
||||
#ifdef FEAT_CRYPT
|
||||
if (flags & FIO_ENCRYPTED)
|
||||
{
|
||||
|
||||
+13
-3
@@ -472,18 +472,28 @@ vim_main2(void)
|
||||
*/
|
||||
if (p_lpl)
|
||||
{
|
||||
char_u *rtp_copy = NULL;
|
||||
|
||||
/* First add all package directories to 'runtimepath', so that their
|
||||
* autoload directories can be found. Only if not done already with a
|
||||
* :packloadall command. */
|
||||
* :packloadall command.
|
||||
* Make a copy of 'runtimepath', so that source_runtime does not use
|
||||
* the pack directories. */
|
||||
if (!did_source_packages)
|
||||
{
|
||||
rtp_copy = vim_strsave(p_rtp);
|
||||
add_pack_start_dirs();
|
||||
}
|
||||
|
||||
source_in_path(rtp_copy == NULL ? p_rtp : rtp_copy,
|
||||
# ifdef VMS /* Somehow VMS doesn't handle the "**". */
|
||||
source_runtime((char_u *)"plugin/*.vim", DIP_ALL | DIP_NOAFTER);
|
||||
(char_u *)"plugin/*.vim",
|
||||
# else
|
||||
source_runtime((char_u *)"plugin/**/*.vim", DIP_ALL | DIP_NOAFTER);
|
||||
(char_u *)"plugin/**/*.vim",
|
||||
# endif
|
||||
DIP_ALL | DIP_NOAFTER);
|
||||
TIME_MSG("loading plugins");
|
||||
vim_free(rtp_copy);
|
||||
|
||||
/* Only source "start" packages if not done already with a :packloadall
|
||||
* command. */
|
||||
|
||||
+23
-9
@@ -3691,16 +3691,30 @@ vim_beep(
|
||||
{
|
||||
if (!((bo_flags & val) || (bo_flags & BO_ALL)))
|
||||
{
|
||||
if (p_vb
|
||||
#ifdef FEAT_GUI
|
||||
/* While the GUI is starting up the termcap is set for the
|
||||
* GUI but the output still goes to a terminal. */
|
||||
&& !(gui.in_use && gui.starting)
|
||||
#ifdef ELAPSED_FUNC
|
||||
static int did_init = FALSE;
|
||||
static ELAPSED_TYPE start_tv;
|
||||
|
||||
/* Only beep once per half a second, otherwise a sequence of beeps
|
||||
* would freeze Vim. */
|
||||
if (!did_init || ELAPSED_FUNC(start_tv) > 500)
|
||||
{
|
||||
did_init = TRUE;
|
||||
ELAPSED_INIT(start_tv);
|
||||
#endif
|
||||
if (p_vb
|
||||
#ifdef FEAT_GUI
|
||||
/* While the GUI is starting up the termcap is set for
|
||||
* the GUI but the output still goes to a terminal. */
|
||||
&& !(gui.in_use && gui.starting)
|
||||
#endif
|
||||
)
|
||||
out_str_cf(T_VB);
|
||||
else
|
||||
out_char(BELL);
|
||||
#ifdef ELAPSED_FUNC
|
||||
}
|
||||
#endif
|
||||
)
|
||||
out_str(T_VB);
|
||||
else
|
||||
out_char(BELL);
|
||||
}
|
||||
|
||||
/* When 'verbose' is set and we are sourcing a script or executing a
|
||||
|
||||
@@ -1636,7 +1636,9 @@ shift_delete_registers()
|
||||
free_yank_all(); /* free register nine */
|
||||
for (n = 9; n > 1; --n)
|
||||
y_regs[n] = y_regs[n - 1];
|
||||
y_previous = y_current = &y_regs[1];
|
||||
y_current = &y_regs[1];
|
||||
if (!y_append)
|
||||
y_previous = y_current;
|
||||
y_regs[1].y_array = NULL; /* set register one to empty */
|
||||
}
|
||||
|
||||
|
||||
@@ -69,9 +69,10 @@ void ex_argdelete(exarg_T *eap);
|
||||
void ex_listdo(exarg_T *eap);
|
||||
void ex_compiler(exarg_T *eap);
|
||||
void ex_runtime(exarg_T *eap);
|
||||
int source_runtime(char_u *name, int flags);
|
||||
int do_in_path(char_u *path, char_u *name, int flags, void (*callback)(char_u *fname, void *ck), void *cookie);
|
||||
int do_in_runtimepath(char_u *name, int flags, void (*callback)(char_u *fname, void *ck), void *cookie);
|
||||
int source_runtime(char_u *name, int flags);
|
||||
int source_in_path(char_u *path, char_u *name, int flags);
|
||||
void add_pack_start_dirs(void);
|
||||
void load_start_packages(void);
|
||||
void ex_packloadall(exarg_T *eap);
|
||||
|
||||
@@ -16,6 +16,7 @@ void out_flush_check(void);
|
||||
void out_trash(void);
|
||||
void out_char(unsigned c);
|
||||
void out_str_nf(char_u *s);
|
||||
void out_str_cf(char_u *s);
|
||||
void out_str(char_u *s);
|
||||
void term_windgoto(int row, int col);
|
||||
void term_cursor_right(int i);
|
||||
|
||||
+69
@@ -2519,6 +2519,75 @@ out_str_nf(char_u *s)
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* A conditional-flushing out_str, mainly for visualbell.
|
||||
* Handles a delay internally, because termlib may not respect the delay or do
|
||||
* it at the wrong time.
|
||||
* Note: Only for terminal strings.
|
||||
*/
|
||||
void
|
||||
out_str_cf(char_u *s)
|
||||
{
|
||||
if (s != NULL && *s)
|
||||
{
|
||||
char_u *p;
|
||||
|
||||
#ifdef FEAT_GUI
|
||||
/* Don't use tputs() when GUI is used, ncurses crashes. */
|
||||
if (gui.in_use)
|
||||
{
|
||||
out_str_nf(s);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
if (out_pos > OUT_SIZE - 20)
|
||||
out_flush();
|
||||
#ifdef HAVE_TGETENT
|
||||
for (p = s; *s; ++s)
|
||||
{
|
||||
/* flush just before delay command */
|
||||
if (*s == '$' && *(s + 1) == '<')
|
||||
{
|
||||
char_u save_c = *s;
|
||||
int duration = atoi((char *)s + 2);
|
||||
|
||||
*s = NUL;
|
||||
tputs((char *)p, 1, TPUTSFUNCAST out_char_nf);
|
||||
*s = save_c;
|
||||
out_flush();
|
||||
#ifdef ELAPSED_FUNC
|
||||
/* Only sleep here if we can limit this happening in
|
||||
* vim_beep(). */
|
||||
p = vim_strchr(s, '>');
|
||||
if (p == NULL || duration <= 0)
|
||||
{
|
||||
/* can't parse the time, don't sleep here */
|
||||
p = s;
|
||||
}
|
||||
else
|
||||
{
|
||||
++p;
|
||||
do_sleep(duration);
|
||||
}
|
||||
#else
|
||||
/* Rely on the terminal library to sleep. */
|
||||
p = s;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
tputs((char *)p, 1, TPUTSFUNCAST out_char_nf);
|
||||
#else
|
||||
while (*s)
|
||||
out_char_nf(*s++);
|
||||
#endif
|
||||
|
||||
/* For testing we write one string at a time. */
|
||||
if (p_wd)
|
||||
out_flush();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* out_str(s): Put a character string a byte at a time into the output buffer.
|
||||
* If HAVE_TGETENT is defined use the termcap parser. (jw)
|
||||
|
||||
@@ -60,10 +60,8 @@ SCRIPTS_ALL = \
|
||||
test77.out \
|
||||
test79.out \
|
||||
test80.out \
|
||||
test82.out \
|
||||
test84.out \
|
||||
test88.out \
|
||||
test90.out \
|
||||
test91.out \
|
||||
test94.out \
|
||||
test95.out \
|
||||
|
||||
@@ -91,8 +91,8 @@ SCRIPT = test1.out test3.out test4.out test5.out \
|
||||
test66.out test67.out test68.out test69.out \
|
||||
test72.out test75.out \
|
||||
test77a.out test78.out test79.out test80.out \
|
||||
test82.out test84.out test88.out \
|
||||
test90.out test91.out test94.out \
|
||||
test84.out test88.out \
|
||||
test91.out test94.out \
|
||||
test95.out test98.out test99.out \
|
||||
test103.out test104.out \
|
||||
test107.out test108.out\
|
||||
|
||||
@@ -1,103 +0,0 @@
|
||||
Tests for case-insensitive UTF-8 comparisons (utf_strnicmp() in mbyte.c)
|
||||
Also test "g~ap".
|
||||
|
||||
STARTTEST
|
||||
:so small.vim
|
||||
:if !has("multi_byte")
|
||||
: e! test.ok
|
||||
: w! test.out
|
||||
: qa!
|
||||
:endif
|
||||
:set enc=utf8
|
||||
ggdG:
|
||||
:
|
||||
:function! Ch(a, op, b, expected)
|
||||
: if eval(printf('"%s" %s "%s"', a:a, a:op, a:b)) != a:expected
|
||||
: call append(line('$'), printf('"%s" %s "%s" should return %d', a:a, a:op, a:b, a:expected))
|
||||
: else
|
||||
: let b:passed += 1
|
||||
: endif
|
||||
:endfunction
|
||||
:
|
||||
:function! Chk(a, b, result)
|
||||
: if a:result == 0
|
||||
: call Ch(a:a, '==?', a:b, 1)
|
||||
: call Ch(a:a, '!=?', a:b, 0)
|
||||
: call Ch(a:a, '<=?', a:b, 1)
|
||||
: call Ch(a:a, '>=?', a:b, 1)
|
||||
: call Ch(a:a, '<?', a:b, 0)
|
||||
: call Ch(a:a, '>?', a:b, 0)
|
||||
: elseif a:result > 0
|
||||
: call Ch(a:a, '==?', a:b, 0)
|
||||
: call Ch(a:a, '!=?', a:b, 1)
|
||||
: call Ch(a:a, '<=?', a:b, 0)
|
||||
: call Ch(a:a, '>=?', a:b, 1)
|
||||
: call Ch(a:a, '<?', a:b, 0)
|
||||
: call Ch(a:a, '>?', a:b, 1)
|
||||
: else
|
||||
: call Ch(a:a, '==?', a:b, 0)
|
||||
: call Ch(a:a, '!=?', a:b, 1)
|
||||
: call Ch(a:a, '<=?', a:b, 1)
|
||||
: call Ch(a:a, '>=?', a:b, 0)
|
||||
: call Ch(a:a, '<?', a:b, 1)
|
||||
: call Ch(a:a, '>?', a:b, 0)
|
||||
: endif
|
||||
:endfunction
|
||||
:
|
||||
:function! Check(a, b, result)
|
||||
: call Chk(a:a, a:b, a:result)
|
||||
: call Chk(a:b, a:a, -a:result)
|
||||
:endfunction
|
||||
:
|
||||
:function! LT(a, b)
|
||||
: call Check(a:a, a:b, -1)
|
||||
:endfunction
|
||||
:
|
||||
:function! GT(a, b)
|
||||
: call Check(a:a, a:b, 1)
|
||||
:endfunction
|
||||
:
|
||||
:function! EQ(a, b)
|
||||
: call Check(a:a, a:b, 0)
|
||||
:endfunction
|
||||
:
|
||||
:let b:passed=0
|
||||
:call EQ('', '')
|
||||
:call LT('', 'a')
|
||||
:call EQ('abc', 'abc')
|
||||
:call EQ('Abc', 'abC')
|
||||
:call LT('ab', 'abc')
|
||||
:call LT('AB', 'abc')
|
||||
:call LT('ab', 'aBc')
|
||||
:call EQ('\xd0\xb9\xd1\x86\xd1\x83\xd0\xba\xd0\xb5\xd0\xbd', '\xd0\xb9\xd0\xa6\xd0\xa3\xd0\xba\xd0\x95\xd0\xbd')
|
||||
:call LT('\xd0\xb9\xd1\x86\xd1\x83\xd0\xba\xd0\xb5\xd0\xbd', '\xd0\xaf\xd1\x86\xd1\x83\xd0\xba\xd0\xb5\xd0\xbd')
|
||||
:call EQ('\xe2\x84\xaa', 'k')
|
||||
:call LT('\xe2\x84\xaa', 'kkkkkk')
|
||||
:call EQ('\xe2\x84\xaa\xe2\x84\xaa\xe2\x84\xaa', 'kkk')
|
||||
:call LT('kk', '\xe2\x84\xaa\xe2\x84\xaa\xe2\x84\xaa')
|
||||
:call EQ('\xe2\x84\xaa\xe2\x84\xa6k\xe2\x84\xaak\xcf\x89', 'k\xcf\x89\xe2\x84\xaakk\xe2\x84\xa6')
|
||||
:call EQ('Abc\x80', 'AbC\x80')
|
||||
:call LT('Abc\x80', 'AbC\x81')
|
||||
:call LT('Abc', 'AbC\x80')
|
||||
:call LT('abc\x80DEF', 'abc\x80def') " case folding stops at the first bad character
|
||||
:call LT('\xc3XYZ', '\xc3xyz')
|
||||
:call EQ('\xef\xbc\xba', '\xef\xbd\x9a') " FF3A (upper), FF5A (lower)
|
||||
:call GT('\xef\xbc\xba', '\xef\xbc\xff') " first string is ok and equals \xef\xbd\x9a after folding, second string is illegal and was left unchanged, then the strings were bytewise compared
|
||||
:call LT('\xc3', '\xc3\x83')
|
||||
:call EQ('\xc3\xa3xYz', '\xc3\x83XyZ')
|
||||
:for n in range(0x60, 0xFF) | call LT(printf('xYz\x%.2X', n-1), printf('XyZ\x%.2X', n)) | endfor
|
||||
:for n in range(0x80, 0xBF) | call EQ(printf('xYz\xc2\x%.2XUvW', n), printf('XyZ\xc2\x%.2XuVw', n)) | endfor
|
||||
:for n in range(0xC0, 0xFF) | call LT(printf('xYz\xc2\x%.2XUvW', n), printf('XyZ\xc2\x%.2XuVw', n)) | endfor
|
||||
:call append(0, printf('%d checks passed', b:passed))
|
||||
:"
|
||||
:" test that g~ap changes one paragraph only.
|
||||
:new
|
||||
iabcd
|
||||
|
||||
defggg0g~ap:let lns = getline(1,3)
|
||||
:q!
|
||||
:call append(line('$'), lns)
|
||||
:"
|
||||
:wq! test.out
|
||||
ENDTEST
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
3732 checks passed
|
||||
|
||||
ABCD
|
||||
|
||||
defg
|
||||
@@ -1,53 +0,0 @@
|
||||
Tests for sha256() function. vim: set ft=vim et ts=2 sw=2 :
|
||||
|
||||
STARTTEST
|
||||
:so small.vim
|
||||
:if !has('cryptv') || !exists('*sha256')
|
||||
e! test.ok
|
||||
wq! test.out
|
||||
:endif
|
||||
:"
|
||||
:let testcase='test for empty string: '
|
||||
:if sha256("") ==# 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'
|
||||
: let res='ok'
|
||||
:else
|
||||
: let res='ng'
|
||||
:endif
|
||||
:$put =testcase.res
|
||||
:"
|
||||
:let testcase='test for 1 char: '
|
||||
:if sha256("a") ==# 'ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb'
|
||||
: let res='ok'
|
||||
:else
|
||||
: let res='ng'
|
||||
:endif
|
||||
:$put =testcase.res
|
||||
:"
|
||||
:let testcase='test for 3 chars: '
|
||||
:if sha256("abc") ==# 'ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad'
|
||||
: let res='ok'
|
||||
:else
|
||||
: let res='ng'
|
||||
:endif
|
||||
:$put =testcase.res
|
||||
:"
|
||||
:let testcase='test for contains meta char: '
|
||||
:if sha256("foo\nbar") ==# '807eff6267f3f926a21d234f7b0cf867a86f47e07a532f15e8cc39ed110ca776'
|
||||
: let res='ok'
|
||||
:else
|
||||
: let res='ng'
|
||||
:endif
|
||||
:$put =testcase.res
|
||||
:"
|
||||
:let testcase='test for contains non-ascii char: '
|
||||
:if sha256("\xde\xad\xbe\xef") ==# '5f78c33274e43fa9de5659265c1d917e25c03722dcb0b8d27db8d5feaa813953'
|
||||
: let res='ok'
|
||||
:else
|
||||
: let res='ng'
|
||||
:endif
|
||||
:$put =testcase.res
|
||||
:"
|
||||
:/^start:/,$wq! test.out
|
||||
ENDTEST
|
||||
|
||||
start:
|
||||
@@ -1,6 +0,0 @@
|
||||
start:
|
||||
test for empty string: ok
|
||||
test for 1 char: ok
|
||||
test for 3 chars: ok
|
||||
test for contains meta char: ok
|
||||
test for contains non-ascii char: ok
|
||||
@@ -34,3 +34,14 @@ func Test_put_char_block2()
|
||||
bw!
|
||||
call setreg('a', a[0], a[1])
|
||||
endfunc
|
||||
|
||||
func Test_put_lines()
|
||||
new
|
||||
let a = [ getreg('a'), getregtype('a') ]
|
||||
call setline(1, ['Line 1', 'Line2', 'Line 3', ''])
|
||||
exe 'norm! gg"add"AddG""p'
|
||||
call assert_equal(['Line 3', '', 'Line 1', 'Line2'], getline(1,'$'))
|
||||
" clean up
|
||||
bw!
|
||||
call setreg('a', a[0], a[1])
|
||||
endfunc
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
" Tests for the sha256() function.
|
||||
|
||||
if !has('cryptv') || !exists('*sha256')
|
||||
finish
|
||||
endif
|
||||
|
||||
function Test_sha256()
|
||||
" test for empty string:
|
||||
call assert_equal(sha256(""), 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855')
|
||||
|
||||
"'test for 1 char:
|
||||
call assert_equal(sha256("a"), 'ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb')
|
||||
"
|
||||
"test for 3 chars:
|
||||
call assert_equal(sha256("abc"), 'ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad')
|
||||
|
||||
" test for contains meta char:
|
||||
call assert_equal(sha256("foo\nbar"), '807eff6267f3f926a21d234f7b0cf867a86f47e07a532f15e8cc39ed110ca776')
|
||||
|
||||
" test for contains non-ascii char:
|
||||
call assert_equal(sha256("\xde\xad\xbe\xef"), '5f78c33274e43fa9de5659265c1d917e25c03722dcb0b8d27db8d5feaa813953')
|
||||
endfunction
|
||||
@@ -23,28 +23,34 @@ func Test_after_comes_later()
|
||||
\ 'set guioptions+=M',
|
||||
\ 'let $HOME = "/does/not/exist"',
|
||||
\ 'set loadplugins',
|
||||
\ 'set rtp=Xhere,Xafter',
|
||||
\ 'set rtp=Xhere,Xafter,Xanother',
|
||||
\ 'set packpath=Xhere,Xafter',
|
||||
\ 'set nomore',
|
||||
\ 'let g:sequence = ""',
|
||||
\ ]
|
||||
let after = [
|
||||
\ 'redir! > Xtestout',
|
||||
\ 'scriptnames',
|
||||
\ 'redir END',
|
||||
\ 'redir! > Xsequence',
|
||||
\ 'echo g:sequence',
|
||||
\ 'redir END',
|
||||
\ 'quit',
|
||||
\ ]
|
||||
call mkdir('Xhere/plugin', 'p')
|
||||
call writefile(['let done = 1'], 'Xhere/plugin/here.vim')
|
||||
call writefile(['let g:sequence .= "here "'], 'Xhere/plugin/here.vim')
|
||||
call mkdir('Xanother/plugin', 'p')
|
||||
call writefile(['let g:sequence .= "another "'], 'Xanother/plugin/another.vim')
|
||||
call mkdir('Xhere/pack/foo/start/foobar/plugin', 'p')
|
||||
call writefile(['let done = 1'], 'Xhere/pack/foo/start/foobar/plugin/foo.vim')
|
||||
call writefile(['let g:sequence .= "pack "'], 'Xhere/pack/foo/start/foobar/plugin/foo.vim')
|
||||
|
||||
call mkdir('Xafter/plugin', 'p')
|
||||
call writefile(['let done = 1'], 'Xafter/plugin/later.vim')
|
||||
call writefile(['let g:sequence .= "after "'], 'Xafter/plugin/later.vim')
|
||||
|
||||
if RunVim(before, after, '')
|
||||
|
||||
let lines = readfile('Xtestout')
|
||||
let expected = ['Xbefore.vim', 'here.vim', 'foo.vim', 'later.vim', 'Xafter.vim']
|
||||
let expected = ['Xbefore.vim', 'here.vim', 'another.vim', 'foo.vim', 'later.vim', 'Xafter.vim']
|
||||
let found = []
|
||||
for line in lines
|
||||
for one in expected
|
||||
@@ -56,8 +62,12 @@ func Test_after_comes_later()
|
||||
call assert_equal(expected, found)
|
||||
endif
|
||||
|
||||
call assert_equal('here another pack after', substitute(join(readfile('Xsequence', 1), ''), '\s\+$', '', ''))
|
||||
|
||||
call delete('Xtestout')
|
||||
call delete('Xsequence')
|
||||
call delete('Xhere', 'rf')
|
||||
call delete('Xanother', 'rf')
|
||||
call delete('Xafter', 'rf')
|
||||
endfunc
|
||||
|
||||
|
||||
@@ -418,7 +418,7 @@ func Test_bg_detection()
|
||||
hi Normal ctermbg=15
|
||||
call assert_equal('light', &bg)
|
||||
|
||||
" manually-set &bg takes precendence over auto-detection
|
||||
" manually-set &bg takes precedence over auto-detection
|
||||
set bg=light
|
||||
hi Normal ctermbg=4
|
||||
call assert_equal('light', &bg)
|
||||
@@ -461,7 +461,6 @@ func Test_syntax_hangs()
|
||||
bwipe!
|
||||
endfunc
|
||||
|
||||
|
||||
func Test_conceal()
|
||||
if !has('conceal')
|
||||
return
|
||||
@@ -497,3 +496,27 @@ func Test_conceal()
|
||||
set conceallevel&
|
||||
bw!
|
||||
endfunc
|
||||
|
||||
fun Test_synstack_synIDtrans()
|
||||
new
|
||||
setfiletype c
|
||||
syntax on
|
||||
call setline(1, ' /* A comment with a TODO */')
|
||||
|
||||
call assert_equal([], synstack(1, 1))
|
||||
|
||||
norm f/
|
||||
call assert_equal(['cComment', 'cCommentStart'], map(synstack(line("."), col(".")), 'synIDattr(v:val, "name")'))
|
||||
call assert_equal(['Comment', 'Comment'], map(synstack(line("."), col(".")), 'synIDattr(synIDtrans(v:val), "name")'))
|
||||
|
||||
norm fA
|
||||
call assert_equal(['cComment'], map(synstack(line("."), col(".")), 'synIDattr(v:val, "name")'))
|
||||
call assert_equal(['Comment'], map(synstack(line("."), col(".")), 'synIDattr(synIDtrans(v:val), "name")'))
|
||||
|
||||
norm fT
|
||||
call assert_equal(['cComment', 'cTodo'], map(synstack(line("."), col(".")), 'synIDattr(v:val, "name")'))
|
||||
call assert_equal(['Comment', 'Todo'], map(synstack(line("."), col(".")), 'synIDattr(synIDtrans(v:val), "name")'))
|
||||
|
||||
syn clear
|
||||
bw!
|
||||
endfunc
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
" Tests for case-insensitive UTF-8 comparisons (utf_strnicmp() in mbyte.c)
|
||||
" Also test "g~ap".
|
||||
|
||||
if !has("multi_byte")
|
||||
finish
|
||||
endif
|
||||
|
||||
function! Ch(a, op, b, expected)
|
||||
call assert_equal(eval(printf('"%s" %s "%s"', a:a, a:op, a:b)), a:expected,
|
||||
\ printf('"%s" %s "%s" should return %d', a:a, a:op, a:b, a:expected))
|
||||
endfunction
|
||||
|
||||
function! Chk(a, b, result)
|
||||
if a:result == 0
|
||||
call Ch(a:a, '==?', a:b, 1)
|
||||
call Ch(a:a, '!=?', a:b, 0)
|
||||
call Ch(a:a, '<=?', a:b, 1)
|
||||
call Ch(a:a, '>=?', a:b, 1)
|
||||
call Ch(a:a, '<?', a:b, 0)
|
||||
call Ch(a:a, '>?', a:b, 0)
|
||||
elseif a:result > 0
|
||||
call Ch(a:a, '==?', a:b, 0)
|
||||
call Ch(a:a, '!=?', a:b, 1)
|
||||
call Ch(a:a, '<=?', a:b, 0)
|
||||
call Ch(a:a, '>=?', a:b, 1)
|
||||
call Ch(a:a, '<?', a:b, 0)
|
||||
call Ch(a:a, '>?', a:b, 1)
|
||||
else
|
||||
call Ch(a:a, '==?', a:b, 0)
|
||||
call Ch(a:a, '!=?', a:b, 1)
|
||||
call Ch(a:a, '<=?', a:b, 1)
|
||||
call Ch(a:a, '>=?', a:b, 0)
|
||||
call Ch(a:a, '<?', a:b, 1)
|
||||
call Ch(a:a, '>?', a:b, 0)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! Check(a, b, result)
|
||||
call Chk(a:a, a:b, a:result)
|
||||
call Chk(a:b, a:a, -a:result)
|
||||
endfunction
|
||||
|
||||
function! LT(a, b)
|
||||
call Check(a:a, a:b, -1)
|
||||
endfunction
|
||||
|
||||
function! GT(a, b)
|
||||
call Check(a:a, a:b, 1)
|
||||
endfunction
|
||||
|
||||
function! EQ(a, b)
|
||||
call Check(a:a, a:b, 0)
|
||||
endfunction
|
||||
|
||||
function Test_comparisons()
|
||||
call EQ('', '')
|
||||
call LT('', 'a')
|
||||
call EQ('abc', 'abc')
|
||||
call EQ('Abc', 'abC')
|
||||
call LT('ab', 'abc')
|
||||
call LT('AB', 'abc')
|
||||
call LT('ab', 'aBc')
|
||||
call EQ('\xd0\xb9\xd1\x86\xd1\x83\xd0\xba\xd0\xb5\xd0\xbd', '\xd0\xb9\xd0\xa6\xd0\xa3\xd0\xba\xd0\x95\xd0\xbd')
|
||||
call LT('\xd0\xb9\xd1\x86\xd1\x83\xd0\xba\xd0\xb5\xd0\xbd', '\xd0\xaf\xd1\x86\xd1\x83\xd0\xba\xd0\xb5\xd0\xbd')
|
||||
call EQ('\xe2\x84\xaa', 'k')
|
||||
call LT('\xe2\x84\xaa', 'kkkkkk')
|
||||
call EQ('\xe2\x84\xaa\xe2\x84\xaa\xe2\x84\xaa', 'kkk')
|
||||
call LT('kk', '\xe2\x84\xaa\xe2\x84\xaa\xe2\x84\xaa')
|
||||
call EQ('\xe2\x84\xaa\xe2\x84\xa6k\xe2\x84\xaak\xcf\x89', 'k\xcf\x89\xe2\x84\xaakk\xe2\x84\xa6')
|
||||
call EQ('Abc\x80', 'AbC\x80')
|
||||
call LT('Abc\x80', 'AbC\x81')
|
||||
call LT('Abc', 'AbC\x80')
|
||||
call LT('abc\x80DEF', 'abc\x80def') " case folding stops at the first bad character
|
||||
call LT('\xc3XYZ', '\xc3xyz')
|
||||
call EQ('\xef\xbc\xba', '\xef\xbd\x9a') " FF3A (upper), FF5A (lower)
|
||||
call GT('\xef\xbc\xba', '\xef\xbc\xff') " first string is ok and equals \xef\xbd\x9a after folding, second string is illegal and was left unchanged, then the strings were bytewise compared
|
||||
call LT('\xc3', '\xc3\x83')
|
||||
call EQ('\xc3\xa3xYz', '\xc3\x83XyZ')
|
||||
for n in range(0x60, 0xFF)
|
||||
call LT(printf('xYz\x%.2X', n-1), printf('XyZ\x%.2X', n))
|
||||
endfor
|
||||
for n in range(0x80, 0xBF)
|
||||
call EQ(printf('xYz\xc2\x%.2XUvW', n), printf('XyZ\xc2\x%.2XuVw', n))
|
||||
endfor
|
||||
for n in range(0xC0, 0xFF)
|
||||
call LT(printf('xYz\xc2\x%.2XUvW', n), printf('XyZ\xc2\x%.2XuVw', n))
|
||||
endfor
|
||||
endfunction
|
||||
|
||||
" test that g~ap changes one paragraph only.
|
||||
function Test_gap()
|
||||
new
|
||||
call feedkeys("iabcd\n\ndefggg0g~ap", "tx")
|
||||
call assert_equal(["ABCD", "", "defg"], getline(1,3))
|
||||
endfunction
|
||||
@@ -31,3 +31,21 @@ func Test_writefile_fails_gently()
|
||||
|
||||
call assert_fails('call writefile([], [])', 'E730:')
|
||||
endfunc
|
||||
|
||||
func Test_writefile_fails_conversion()
|
||||
if !has('multi_byte') || !has('iconv')
|
||||
return
|
||||
endif
|
||||
set nobackup nowritebackup
|
||||
new
|
||||
let contents = ["line one", "line two"]
|
||||
call writefile(contents, 'Xfile')
|
||||
edit Xfile
|
||||
call setline(1, ["first line", "cannot convert \u010b", "third line"])
|
||||
call assert_fails('write ++enc=cp932')
|
||||
call assert_equal(contents, readfile('Xfile'))
|
||||
|
||||
call delete('Xfile')
|
||||
bwipe!
|
||||
set backup& writebackup&
|
||||
endfunc
|
||||
|
||||
@@ -779,6 +779,18 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
685,
|
||||
/**/
|
||||
684,
|
||||
/**/
|
||||
683,
|
||||
/**/
|
||||
682,
|
||||
/**/
|
||||
681,
|
||||
/**/
|
||||
680,
|
||||
/**/
|
||||
679,
|
||||
/**/
|
||||
|
||||
Reference in New Issue
Block a user