mirror of
https://github.com/zoriya/vim.git
synced 2025-12-09 08:46:17 +00:00
Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9c4fefffb6 | ||
|
|
86f100dc09 | ||
|
|
9f5f7bf4d5 | ||
|
|
e6bf655bc4 | ||
|
|
28b238225a | ||
|
|
2e147caa14 | ||
|
|
0b2eef24bc | ||
|
|
18d90b95c4 | ||
|
|
07ecfa64a1 | ||
|
|
41cc038ff8 | ||
|
|
8eeeba8c02 | ||
|
|
1814183b86 | ||
|
|
182a17b1e8 | ||
|
|
774e5a9673 | ||
|
|
5d7be4f0fa | ||
|
|
ea20de8146 | ||
|
|
cc0750dc6e | ||
|
|
4eb6531b03 | ||
|
|
1e8e14552e | ||
|
|
24a9e348aa | ||
|
|
a1bd86e0f2 | ||
|
|
53564f7c1a | ||
|
|
5fe691240b | ||
|
|
090209bfbd | ||
|
|
6d006f9e95 |
@@ -87,7 +87,8 @@ UninstPage instfiles
|
||||
Function .onInit
|
||||
MessageBox MB_YESNO|MB_ICONQUESTION \
|
||||
"This will install Vim ${VER_MAJOR}.${VER_MINOR} on your computer.$\n Continue?" \
|
||||
/SD IDYES NoAbort
|
||||
/SD IDYES \
|
||||
IDYES NoAbort
|
||||
Abort ; causes installer to quit.
|
||||
NoAbort:
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
*eval.txt* For Vim version 8.0. Last change: 2017 Jun 23
|
||||
*eval.txt* For Vim version 8.0. Last change: 2017 Jun 25
|
||||
|
||||
|
||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||
@@ -7008,7 +7008,8 @@ setqflist({list} [, {action}[, {what}]]) *setqflist()*
|
||||
title quickfix list title text
|
||||
Unsupported keys in {what} are ignored.
|
||||
If the "nr" item is not present, then the current quickfix list
|
||||
is modified.
|
||||
is modified. When creating a new quickfix list, "nr" can be
|
||||
set to a value one greater than the quickfix stack size.
|
||||
|
||||
Examples: >
|
||||
:call setqflist([], 'r', {'title': 'My search'})
|
||||
@@ -7663,12 +7664,21 @@ synconcealed({lnum}, {col}) *synconcealed()*
|
||||
is 1, the second item contains the text which will be
|
||||
displayed in place of the concealed text, depending on the
|
||||
current setting of 'conceallevel' and 'listchars'.
|
||||
3. The third and final item in the list is a unique number
|
||||
representing the specific syntax region matched. This
|
||||
allows detection of the beginning of a new concealable
|
||||
region if there are two consecutive regions with the same
|
||||
replacement character. For an example use see
|
||||
$VIMRUNTIME/syntax/2html.vim .
|
||||
3. The third and final item in the list is a number
|
||||
representing the specific syntax region matched in the
|
||||
line. When the character is not concealed the value is
|
||||
zero. This allows detection of the beginning of a new
|
||||
concealable region if there are two consecutive regions
|
||||
with the same replacement character. For an example, if
|
||||
the text is "123456" and both "23" and "45" are concealed
|
||||
and replace by the character "X", then:
|
||||
call returns ~
|
||||
synconcealed(lnum, 1) [0, '', 0]
|
||||
synconcealed(lnum, 2) [1, 'X', 1]
|
||||
synconcealed(lnum, 3) [1, 'X', 1]
|
||||
synconcealed(lnum, 4) [1, 'X', 2]
|
||||
synconcealed(lnum, 5) [1, 'X', 2]
|
||||
synconcealed(lnum, 6) [0, '', 0]
|
||||
|
||||
|
||||
synstack({lnum}, {col}) *synstack()*
|
||||
@@ -7933,8 +7943,19 @@ test_override({name}, {val}) *test_override()*
|
||||
name effect when {val} is non-zero ~
|
||||
redraw disable the redrawing() function
|
||||
char_avail disable the char_avail() function
|
||||
starting reset the "starting" variable, see below
|
||||
ALL clear all overrides ({val} is not used)
|
||||
|
||||
"starting" is to be used when a test should behave like
|
||||
startup was done. Since the tests are run by sourcing a
|
||||
script the "starting" variable is non-zero. This is usually a
|
||||
good thing (tests run faster), but sometimes changes behavior
|
||||
in a way that the test doesn't work properly.
|
||||
When using: >
|
||||
call test_override('starting', 1)
|
||||
< The value of "starting" is saved. It is restored by: >
|
||||
call test_override('starting', 0)
|
||||
|
||||
test_settime({expr}) *test_settime()*
|
||||
Set the time Vim uses internally. Currently only used for
|
||||
timestamps in the history, as they are used in viminfo, and
|
||||
|
||||
@@ -2089,8 +2089,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)
|
||||
|
||||
@@ -2207,6 +2207,7 @@ test_arglist \
|
||||
test_search \
|
||||
test_searchpos \
|
||||
test_set \
|
||||
test_sha256 \
|
||||
test_signs \
|
||||
test_smartindent \
|
||||
test_sort \
|
||||
@@ -2233,6 +2234,7 @@ test_arglist \
|
||||
test_unlet \
|
||||
test_usercommands \
|
||||
test_utf8 \
|
||||
test_utf8_comparisons \
|
||||
test_viminfo \
|
||||
test_vimscript \
|
||||
test_visual \
|
||||
|
||||
14
src/edit.c
14
src/edit.c
@@ -4308,9 +4308,17 @@ ins_compl_get_exp(pos_T *ini)
|
||||
{
|
||||
ins_buf = curbuf;
|
||||
first_match_pos = *ini;
|
||||
/* So that ^N can match word immediately after cursor */
|
||||
if (ctrl_x_mode == 0)
|
||||
dec(&first_match_pos);
|
||||
/* Move the cursor back one character so that ^N can match the
|
||||
* word immediately after the cursor. */
|
||||
if (ctrl_x_mode == 0 && dec(&first_match_pos) < 0)
|
||||
{
|
||||
/* Move the cursor to after the last character in the
|
||||
* buffer, so that word at start of buffer is found
|
||||
* correctly. */
|
||||
first_match_pos.lnum = ins_buf->b_ml.ml_line_count;
|
||||
first_match_pos.col =
|
||||
(colnr_T)STRLEN(ml_get(first_match_pos.lnum));
|
||||
}
|
||||
last_match_pos = first_match_pos;
|
||||
type = 0;
|
||||
|
||||
|
||||
@@ -3191,7 +3191,11 @@ f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
|
||||
ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
|
||||
insert ? 0 : typebuf.tb_len, !typed, FALSE);
|
||||
vim_free(keys_esc);
|
||||
if (vgetc_busy)
|
||||
if (vgetc_busy
|
||||
#ifdef FEAT_TIMERS
|
||||
|| timer_busy
|
||||
#endif
|
||||
)
|
||||
typebuf_was_filled = TRUE;
|
||||
if (execute)
|
||||
{
|
||||
@@ -12394,6 +12398,7 @@ f_test_override(typval_T *argvars, typval_T *rettv UNUSED)
|
||||
{
|
||||
char_u *name = (char_u *)"";
|
||||
int val;
|
||||
static int save_starting = -1;
|
||||
|
||||
if (argvars[0].v_type != VAR_STRING
|
||||
|| (argvars[1].v_type) != VAR_NUMBER)
|
||||
@@ -12407,10 +12412,29 @@ f_test_override(typval_T *argvars, typval_T *rettv UNUSED)
|
||||
disable_redraw_for_testing = val;
|
||||
else if (STRCMP(name, (char_u *)"char_avail") == 0)
|
||||
disable_char_avail_for_testing = val;
|
||||
else if (STRCMP(name, (char_u *)"starting") == 0)
|
||||
{
|
||||
if (val)
|
||||
{
|
||||
if (save_starting < 0)
|
||||
save_starting = starting;
|
||||
starting = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
starting = save_starting;
|
||||
save_starting = -1;
|
||||
}
|
||||
}
|
||||
else if (STRCMP(name, (char_u *)"ALL") == 0)
|
||||
{
|
||||
disable_char_avail_for_testing = FALSE;
|
||||
disable_redraw_for_testing = FALSE;
|
||||
if (save_starting >= 0)
|
||||
{
|
||||
starting = save_starting;
|
||||
save_starting = -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
EMSG2(_(e_invarg2), name);
|
||||
|
||||
@@ -6835,7 +6835,11 @@ fix_help_buffer(void)
|
||||
#ifdef FEAT_AUTOCMD
|
||||
/* Set filetype to "help" if still needed. */
|
||||
if (STRCMP(curbuf->b_p_ft, "help") != 0)
|
||||
{
|
||||
++curbuf_lock;
|
||||
set_option_value((char_u *)"ft", 0L, (char_u *)"help", OPT_LOCAL);
|
||||
--curbuf_lock;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef FEAT_SYN_HL
|
||||
|
||||
@@ -51,7 +51,9 @@
|
||||
#define BUFUNL 0x20000L /* accepts unlisted buffer too */
|
||||
#define ARGOPT 0x40000L /* allow "++opt=val" argument */
|
||||
#define SBOXOK 0x80000L /* allowed in the sandbox */
|
||||
#define CMDWIN 0x100000L /* allowed in cmdline window */
|
||||
#define CMDWIN 0x100000L /* allowed in cmdline window; when missing
|
||||
* disallows editing another buffer when
|
||||
* curbuf_lock is set */
|
||||
#define MODIFY 0x200000L /* forbidden in non-'modifiable' buffer */
|
||||
#define EXFLAGS 0x400000L /* allow flags after count in argument */
|
||||
#define FILES (XFILE | EXTRA) /* multiple extra files allowed */
|
||||
@@ -1176,7 +1178,7 @@ EX(CMD_registers, "registers", ex_display,
|
||||
EXTRA|NOTRLCOM|TRLBAR|CMDWIN,
|
||||
ADDR_LINES),
|
||||
EX(CMD_resize, "resize", ex_resize,
|
||||
RANGE|NOTADR|TRLBAR|WORD1,
|
||||
RANGE|NOTADR|TRLBAR|WORD1|CMDWIN,
|
||||
ADDR_LINES),
|
||||
EX(CMD_retab, "retab", ex_retab,
|
||||
TRLBAR|RANGE|WHOLEFOLD|DFLALL|BANG|WORD1|CMDWIN|MODIFY,
|
||||
|
||||
@@ -1209,11 +1209,18 @@ check_due_timer(void)
|
||||
this_due = GET_TIMEDIFF(timer, now);
|
||||
if (this_due <= 1)
|
||||
{
|
||||
int save_timer_busy = timer_busy;
|
||||
int save_vgetc_busy = vgetc_busy;
|
||||
|
||||
timer_busy = timer_busy > 0 || vgetc_busy > 0;
|
||||
vgetc_busy = 0;
|
||||
timer->tr_firing = TRUE;
|
||||
timer_callback(timer);
|
||||
timer->tr_firing = FALSE;
|
||||
timer_next = timer->tr_next;
|
||||
did_one = TRUE;
|
||||
timer_busy = save_timer_busy;
|
||||
vgetc_busy = save_vgetc_busy;
|
||||
|
||||
/* Only fire the timer again if it repeats and stop_timer() wasn't
|
||||
* called while inside the callback (tr_id == -1). */
|
||||
@@ -3278,19 +3285,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)".
|
||||
@@ -3428,18 +3422,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),
|
||||
@@ -3452,7 +3447,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))
|
||||
{
|
||||
@@ -3479,6 +3474,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.
|
||||
*/
|
||||
|
||||
@@ -6878,6 +6878,8 @@ open_cmdwin(void)
|
||||
# ifdef FEAT_AUTOCMD
|
||||
/* Do execute autocommands for setting the filetype (load syntax). */
|
||||
unblock_autocmds();
|
||||
/* But don't allow switching to another buffer. */
|
||||
++curbuf_lock;
|
||||
# endif
|
||||
|
||||
/* Showing the prompt may have set need_wait_return, reset it. */
|
||||
@@ -6893,6 +6895,9 @@ open_cmdwin(void)
|
||||
}
|
||||
set_option_value((char_u *)"ft", 0L, (char_u *)"vim", OPT_LOCAL);
|
||||
}
|
||||
# ifdef FEAT_AUTOCMD
|
||||
--curbuf_lock;
|
||||
# endif
|
||||
|
||||
/* Reset 'textwidth' after setting 'filetype' (the Vim filetype plugin
|
||||
* sets 'textwidth' to 78). */
|
||||
|
||||
771
src/fileio.c
771
src/fileio.c
@@ -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
|
||||
@@ -5690,6 +5749,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)
|
||||
{
|
||||
|
||||
@@ -467,6 +467,11 @@ flush_buffers(int flush_typeahead)
|
||||
;
|
||||
typebuf.tb_off = MAXMAPLEN;
|
||||
typebuf.tb_len = 0;
|
||||
#if defined(FEAT_CLIENTSERVER) || defined(FEAT_EVAL)
|
||||
/* Reset the flag that text received from a client or from feedkeys()
|
||||
* was inserted in the typeahead buffer. */
|
||||
typebuf_was_filled = FALSE;
|
||||
#endif
|
||||
}
|
||||
else /* remove mapped characters at the start only */
|
||||
{
|
||||
|
||||
@@ -1659,6 +1659,7 @@ EXTERN int in_free_unref_items INIT(= FALSE);
|
||||
|
||||
#ifdef FEAT_TIMERS
|
||||
EXTERN int did_add_timer INIT(= FALSE);
|
||||
EXTERN int timer_busy INIT(= 0); /* when timer is inside vgetc() then > 0 */
|
||||
#endif
|
||||
|
||||
#ifdef FEAT_EVAL
|
||||
|
||||
16
src/main.c
16
src/main.c
@@ -449,18 +449,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. */
|
||||
|
||||
32
src/misc1.c
32
src/misc1.c
@@ -3685,16 +3685,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 */
|
||||
}
|
||||
|
||||
|
||||
78
src/option.c
78
src/option.c
@@ -4294,6 +4294,32 @@ set_title_defaults(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
|
||||
static void
|
||||
trigger_optionsset_string(
|
||||
int opt_idx,
|
||||
int opt_flags,
|
||||
char_u *oldval,
|
||||
char_u *newval)
|
||||
{
|
||||
if (oldval != NULL && newval != NULL)
|
||||
{
|
||||
char_u buf_type[7];
|
||||
|
||||
sprintf((char *)buf_type, "%s",
|
||||
(opt_flags & OPT_LOCAL) ? "local" : "global");
|
||||
set_vim_var_string(VV_OPTION_OLD, oldval, -1);
|
||||
set_vim_var_string(VV_OPTION_NEW, newval, -1);
|
||||
set_vim_var_string(VV_OPTION_TYPE, buf_type, -1);
|
||||
apply_autocmds(EVENT_OPTIONSET,
|
||||
(char_u *)options[opt_idx].fullname, NULL, FALSE, NULL);
|
||||
reset_v_option_vars();
|
||||
}
|
||||
vim_free(oldval);
|
||||
vim_free(newval);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Parse 'arg' for option settings.
|
||||
*
|
||||
@@ -4763,6 +4789,7 @@ do_set(
|
||||
char_u *origval = NULL;
|
||||
#if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
|
||||
char_u *saved_origval = NULL;
|
||||
char_u *saved_newval = NULL;
|
||||
#endif
|
||||
unsigned newlen;
|
||||
int comma;
|
||||
@@ -5114,14 +5141,21 @@ do_set(
|
||||
# ifdef FEAT_CRYPT
|
||||
&& options[opt_idx].indir != PV_KEY
|
||||
# endif
|
||||
&& origval != NULL)
|
||||
&& origval != NULL && newval != NULL)
|
||||
{
|
||||
/* origval may be freed by
|
||||
* did_set_string_option(), make a copy. */
|
||||
saved_origval = vim_strsave(origval);
|
||||
/* newval (and varp) may become invalid if the
|
||||
* buffer is closed by autocommands. */
|
||||
saved_newval = vim_strsave(newval);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Handle side effects, and set the global value for
|
||||
* ":set" on local options. */
|
||||
* ":set" on local options. Note: when setting 'syntax'
|
||||
* or 'filetype' autocommands may be triggered that can
|
||||
* cause havoc. */
|
||||
errmsg = did_set_string_option(opt_idx, (char_u **)varp,
|
||||
new_value_alloced, oldval, errbuf, opt_flags);
|
||||
|
||||
@@ -5130,28 +5164,14 @@ do_set(
|
||||
{
|
||||
#if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
|
||||
vim_free(saved_origval);
|
||||
vim_free(saved_newval);
|
||||
#endif
|
||||
goto skip;
|
||||
}
|
||||
#if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
|
||||
if (saved_origval != NULL)
|
||||
{
|
||||
char_u buf_type[7];
|
||||
|
||||
sprintf((char *)buf_type, "%s",
|
||||
(opt_flags & OPT_LOCAL) ? "local" : "global");
|
||||
set_vim_var_string(VV_OPTION_NEW,
|
||||
*(char_u **)varp, -1);
|
||||
set_vim_var_string(VV_OPTION_OLD, saved_origval, -1);
|
||||
set_vim_var_string(VV_OPTION_TYPE, buf_type, -1);
|
||||
apply_autocmds(EVENT_OPTIONSET,
|
||||
(char_u *)options[opt_idx].fullname,
|
||||
NULL, FALSE, NULL);
|
||||
reset_v_option_vars();
|
||||
vim_free(saved_origval);
|
||||
}
|
||||
trigger_optionsset_string(opt_idx, opt_flags,
|
||||
saved_origval, saved_newval);
|
||||
#endif
|
||||
|
||||
}
|
||||
else /* key code option */
|
||||
{
|
||||
@@ -5922,6 +5942,7 @@ set_string_option(
|
||||
char_u *oldval;
|
||||
#if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
|
||||
char_u *saved_oldval = NULL;
|
||||
char_u *saved_newval = NULL;
|
||||
#endif
|
||||
char_u *r = NULL;
|
||||
|
||||
@@ -5945,26 +5966,19 @@ set_string_option(
|
||||
&& options[opt_idx].indir != PV_KEY
|
||||
# endif
|
||||
)
|
||||
{
|
||||
saved_oldval = vim_strsave(oldval);
|
||||
saved_newval = vim_strsave(s);
|
||||
}
|
||||
#endif
|
||||
if ((r = did_set_string_option(opt_idx, varp, TRUE, oldval, NULL,
|
||||
opt_flags)) == NULL)
|
||||
did_set_option(opt_idx, opt_flags, TRUE);
|
||||
|
||||
/* call autocommand after handling side effects */
|
||||
#if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
|
||||
if (saved_oldval != NULL)
|
||||
{
|
||||
char_u buf_type[7];
|
||||
sprintf((char *)buf_type, "%s",
|
||||
(opt_flags & OPT_LOCAL) ? "local" : "global");
|
||||
set_vim_var_string(VV_OPTION_NEW, *varp, -1);
|
||||
set_vim_var_string(VV_OPTION_OLD, saved_oldval, -1);
|
||||
set_vim_var_string(VV_OPTION_TYPE, buf_type, -1);
|
||||
apply_autocmds(EVENT_OPTIONSET, (char_u *)options[opt_idx].fullname, NULL, FALSE, NULL);
|
||||
reset_v_option_vars();
|
||||
vim_free(saved_oldval);
|
||||
}
|
||||
/* call autocommand after handling side effects */
|
||||
trigger_optionsset_string(opt_idx, opt_flags,
|
||||
saved_oldval, saved_newval);
|
||||
#endif
|
||||
}
|
||||
return r;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -1163,8 +1163,8 @@ qf_init_ext(
|
||||
qffields_T fields;
|
||||
#ifdef FEAT_WINDOWS
|
||||
qfline_T *old_last = NULL;
|
||||
int adding = FALSE;
|
||||
#endif
|
||||
int adding = FALSE;
|
||||
static efm_T *fmt_first = NULL;
|
||||
char_u *efm;
|
||||
static char_u *last_efm = NULL;
|
||||
@@ -1199,14 +1199,15 @@ qf_init_ext(
|
||||
if (newlist || qi->qf_curlist == qi->qf_listcount)
|
||||
/* make place for a new list */
|
||||
qf_new_list(qi, qf_title);
|
||||
#ifdef FEAT_WINDOWS
|
||||
else if (qi->qf_lists[qi->qf_curlist].qf_count > 0)
|
||||
else
|
||||
{
|
||||
/* Adding to existing list, use last entry. */
|
||||
adding = TRUE;
|
||||
old_last = qi->qf_lists[qi->qf_curlist].qf_last;
|
||||
}
|
||||
#ifdef FEAT_WINDOWS
|
||||
if (qi->qf_lists[qi->qf_curlist].qf_count > 0)
|
||||
old_last = qi->qf_lists[qi->qf_curlist].qf_last;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Use the local value of 'errorformat' if it's set. */
|
||||
if (errorformat == p_efm && tv == NULL && *buf->b_p_efm != NUL)
|
||||
@@ -3425,6 +3426,9 @@ qf_fill_buffer(qf_info_T *qi, buf_T *buf, qfline_T *old_last)
|
||||
/* Set the 'filetype' to "qf" each time after filling the buffer.
|
||||
* This resembles reading a file into a buffer, it's more logical when
|
||||
* using autocommands. */
|
||||
#ifdef FEAT_AUTOCMD
|
||||
++curbuf_lock;
|
||||
#endif
|
||||
set_option_value((char_u *)"ft", 0L, (char_u *)"qf", OPT_LOCAL);
|
||||
curbuf->b_p_ma = FALSE;
|
||||
|
||||
@@ -3435,6 +3439,7 @@ qf_fill_buffer(qf_info_T *qi, buf_T *buf, qfline_T *old_last)
|
||||
apply_autocmds(EVENT_BUFWINENTER, (char_u *)"quickfix", NULL,
|
||||
FALSE, curbuf);
|
||||
keep_filetype = FALSE;
|
||||
--curbuf_lock;
|
||||
#endif
|
||||
/* make sure it will be redrawn */
|
||||
redraw_curbuf_later(NOT_VALID);
|
||||
@@ -4781,6 +4786,8 @@ get_errorlist_properties(win_T *wp, dict_T *what, dict_T *retdict)
|
||||
(void)get_errorlist(wp, qf_idx, l);
|
||||
dict_add_list(retdict, "items", l);
|
||||
}
|
||||
else
|
||||
status = FAIL;
|
||||
}
|
||||
|
||||
if ((status == OK) && (flags & QF_GETLIST_CONTEXT))
|
||||
@@ -4791,9 +4798,12 @@ get_errorlist_properties(win_T *wp, dict_T *what, dict_T *retdict)
|
||||
if (di != NULL)
|
||||
{
|
||||
copy_tv(qi->qf_lists[qf_idx].qf_ctx, &di->di_tv);
|
||||
if (dict_add(retdict, di) == FAIL)
|
||||
status = dict_add(retdict, di);
|
||||
if (status == FAIL)
|
||||
dictitem_free(di);
|
||||
}
|
||||
else
|
||||
status = FAIL;
|
||||
}
|
||||
else
|
||||
status = dict_add_nr_str(retdict, "context", 0L, (char_u *)"");
|
||||
@@ -5016,6 +5026,7 @@ qf_set_properties(qf_info_T *qi, dict_T *what, int action)
|
||||
if (ctx != NULL)
|
||||
copy_tv(&di->di_tv, ctx);
|
||||
qi->qf_lists[qf_idx].qf_ctx = ctx;
|
||||
retval = OK;
|
||||
}
|
||||
|
||||
return retval;
|
||||
|
||||
@@ -648,6 +648,8 @@ update_screen(int type_arg)
|
||||
{
|
||||
screenclear(); /* will reset clear_cmdline */
|
||||
type = NOT_VALID;
|
||||
/* must_redraw may be set indirectly, avoid another redraw later */
|
||||
must_redraw = 0;
|
||||
}
|
||||
|
||||
if (clear_cmdline) /* going to clear cmdline (done below) */
|
||||
@@ -5502,7 +5504,8 @@ win_line(
|
||||
* Also highlight the 'colorcolumn' if it is different than
|
||||
* 'cursorcolumn' */
|
||||
vcol_save_attr = -1;
|
||||
if (draw_state == WL_LINE && !lnum_in_visual_area)
|
||||
if (draw_state == WL_LINE && !lnum_in_visual_area
|
||||
&& search_attr == 0 && area_attr == 0)
|
||||
{
|
||||
if (wp->w_p_cuc && VCOL_HLC == (long)wp->w_virtcol
|
||||
&& lnum != wp->w_cursor.lnum)
|
||||
|
||||
@@ -1061,6 +1061,9 @@ syn_start_line(void)
|
||||
|
||||
next_match_idx = -1;
|
||||
++current_line_id;
|
||||
#ifdef FEAT_CONCEAL
|
||||
next_seqnr = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1857,6 +1860,7 @@ get_syntax_attr(
|
||||
#endif
|
||||
#ifdef FEAT_CONCEAL
|
||||
current_flags = 0;
|
||||
current_seqnr = 0;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
@@ -2346,6 +2350,7 @@ syn_current_attr(
|
||||
#endif
|
||||
#ifdef FEAT_CONCEAL
|
||||
current_flags = 0;
|
||||
current_seqnr = 0;
|
||||
#endif
|
||||
if (cur_si != NULL)
|
||||
{
|
||||
|
||||
168
src/term.c
168
src/term.c
@@ -1801,9 +1801,8 @@ set_termname(char_u *term)
|
||||
* The termcode for the mouse is added as a side effect in option.c.
|
||||
*/
|
||||
{
|
||||
char_u *p;
|
||||
char_u *p = (char_u *)"";
|
||||
|
||||
p = (char_u *)"";
|
||||
# ifdef FEAT_MOUSE_XTERM
|
||||
if (use_xterm_like_mouse(term))
|
||||
{
|
||||
@@ -1944,6 +1943,7 @@ set_termname(char_u *term)
|
||||
# define HMT_PTERM 16
|
||||
# define HMT_URXVT 32
|
||||
# define HMT_SGR 64
|
||||
# define HMT_SGR_REL 128
|
||||
static int has_mouse_termcode = 0;
|
||||
# endif
|
||||
|
||||
@@ -1987,6 +1987,8 @@ set_mouse_termcode(
|
||||
# ifdef FEAT_MOUSE_SGR
|
||||
if (n == KS_SGR_MOUSE)
|
||||
has_mouse_termcode |= HMT_SGR;
|
||||
else if (n == KS_SGR_MOUSE_RELEASE)
|
||||
has_mouse_termcode |= HMT_SGR_REL;
|
||||
else
|
||||
# endif
|
||||
has_mouse_termcode |= HMT_NORMAL;
|
||||
@@ -2034,6 +2036,8 @@ del_mouse_termcode(
|
||||
# ifdef FEAT_MOUSE_SGR
|
||||
if (n == KS_SGR_MOUSE)
|
||||
has_mouse_termcode &= ~HMT_SGR;
|
||||
else if (n == KS_SGR_MOUSE_RELEASE)
|
||||
has_mouse_termcode &= ~HMT_SGR_REL;
|
||||
else
|
||||
# endif
|
||||
has_mouse_termcode &= ~HMT_NORMAL;
|
||||
@@ -2509,6 +2513,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)
|
||||
@@ -3940,7 +4013,7 @@ check_termcode(
|
||||
int offset;
|
||||
char_u key_name[2];
|
||||
int modifiers;
|
||||
char_u *modifiers_start;
|
||||
char_u *modifiers_start = NULL;
|
||||
int key;
|
||||
int new_slen;
|
||||
int extra;
|
||||
@@ -4597,59 +4670,54 @@ check_termcode(
|
||||
|| key_name[0] == KS_SGR_MOUSE
|
||||
|| key_name[0] == KS_SGR_MOUSE_RELEASE)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
/* URXVT 1015 mouse reporting mode:
|
||||
* Almost identical to xterm mouse mode, except the values
|
||||
* are decimal instead of bytes.
|
||||
*
|
||||
* \033[%d;%d;%dM
|
||||
* ^-- row
|
||||
* ^----- column
|
||||
* ^-------- code
|
||||
*
|
||||
* SGR 1006 mouse reporting mode:
|
||||
* Almost identical to xterm mouse mode, except the values
|
||||
* are decimal instead of bytes.
|
||||
*
|
||||
* \033[<%d;%d;%dM
|
||||
* ^-- row
|
||||
* ^----- column
|
||||
* ^-------- code
|
||||
*
|
||||
* \033[<%d;%d;%dm : mouse release event
|
||||
* ^-- row
|
||||
* ^----- column
|
||||
* ^-------- code
|
||||
*/
|
||||
p = modifiers_start;
|
||||
if (p == NULL)
|
||||
return -1;
|
||||
/* URXVT 1015 mouse reporting mode:
|
||||
* Almost identical to xterm mouse mode, except the values
|
||||
* are decimal instead of bytes.
|
||||
*
|
||||
* \033[%d;%d;%dM
|
||||
* ^-- row
|
||||
* ^----- column
|
||||
* ^-------- code
|
||||
*
|
||||
* SGR 1006 mouse reporting mode:
|
||||
* Almost identical to xterm mouse mode, except the values
|
||||
* are decimal instead of bytes.
|
||||
*
|
||||
* \033[<%d;%d;%dM
|
||||
* ^-- row
|
||||
* ^----- column
|
||||
* ^-------- code
|
||||
*
|
||||
* \033[<%d;%d;%dm : mouse release event
|
||||
* ^-- row
|
||||
* ^----- column
|
||||
* ^-------- code
|
||||
*/
|
||||
p = modifiers_start;
|
||||
if (p == NULL)
|
||||
return -1;
|
||||
|
||||
mouse_code = getdigits(&p);
|
||||
if (*p++ != ';')
|
||||
return -1;
|
||||
mouse_code = getdigits(&p);
|
||||
if (*p++ != ';')
|
||||
return -1;
|
||||
|
||||
/* when mouse reporting is SGR, add 32 to mouse code */
|
||||
if (key_name[0] == KS_SGR_MOUSE
|
||||
|| key_name[0] == KS_SGR_MOUSE_RELEASE)
|
||||
mouse_code += 32;
|
||||
/* when mouse reporting is SGR, add 32 to mouse code */
|
||||
if (key_name[0] == KS_SGR_MOUSE
|
||||
|| key_name[0] == KS_SGR_MOUSE_RELEASE)
|
||||
mouse_code += 32;
|
||||
|
||||
if (key_name[0] == KS_SGR_MOUSE_RELEASE)
|
||||
mouse_code |= MOUSE_RELEASE;
|
||||
if (key_name[0] == KS_SGR_MOUSE_RELEASE)
|
||||
mouse_code |= MOUSE_RELEASE;
|
||||
|
||||
mouse_col = getdigits(&p) - 1;
|
||||
if (*p++ != ';')
|
||||
return -1;
|
||||
mouse_col = getdigits(&p) - 1;
|
||||
if (*p++ != ';')
|
||||
return -1;
|
||||
|
||||
mouse_row = getdigits(&p) - 1;
|
||||
mouse_row = getdigits(&p) - 1;
|
||||
|
||||
/* The modifiers were the mouse coordinates, not the
|
||||
* modifier keys (alt/shift/ctrl/meta) state. */
|
||||
modifiers = 0;
|
||||
|
||||
break;
|
||||
}
|
||||
/* The modifiers were the mouse coordinates, not the
|
||||
* modifier keys (alt/shift/ctrl/meta) state. */
|
||||
modifiers = 0;
|
||||
}
|
||||
# endif
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -194,6 +194,21 @@ func Test_multibyte_sign_and_colorcolumn()
|
||||
call s:close_windows()
|
||||
endfunc
|
||||
|
||||
func Test_colorcolumn_priority()
|
||||
call s:test_windows('setl cc=4 cuc hls')
|
||||
call setline(1, ["xxyy", ""])
|
||||
norm! gg
|
||||
exe "normal! /xxyy\<CR>"
|
||||
norm! G
|
||||
redraw!
|
||||
let line_attr = s:screen_attr(1, [1, &cc])
|
||||
" Search wins over CursorColumn
|
||||
call assert_equal(line_attr[1], line_attr[0])
|
||||
" Search wins over Colorcolumn
|
||||
call assert_equal(line_attr[2], line_attr[3])
|
||||
call s:close_windows('setl hls&vim')
|
||||
endfunc
|
||||
|
||||
func Test_illegal_byte_and_breakat()
|
||||
call s:test_windows("setl sbr= brk+=<")
|
||||
vert resize 18
|
||||
|
||||
@@ -612,5 +612,19 @@ func Test_complete_func_mess()
|
||||
set completefunc=
|
||||
endfunc
|
||||
|
||||
func Test_complete_CTRLN_startofbuffer()
|
||||
new
|
||||
call setline(1, [ 'organize(cupboard, 3, 2);',
|
||||
\ 'prioritize(bureau, 8, 7);',
|
||||
\ 'realize(bannister, 4, 4);',
|
||||
\ 'moralize(railing, 3,9);'])
|
||||
let expected=['cupboard.organize(3, 2);',
|
||||
\ 'bureau.prioritize(8, 7);',
|
||||
\ 'bannister.realize(4, 4);',
|
||||
\ 'railing.moralize(3,9);']
|
||||
call feedkeys("qai\<c-n>\<c-n>.\<esc>3wdW\<cr>q3@a", 'tx')
|
||||
call assert_equal(expected, getline(1,'$'))
|
||||
bwipe!
|
||||
endfunc
|
||||
|
||||
" vim: shiftwidth=2 sts=2 expandtab
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1720,7 +1720,8 @@ func Xproperty_tests(cchar)
|
||||
Xopen
|
||||
wincmd p
|
||||
call g:Xsetlist([{'filename':'foo', 'lnum':27}])
|
||||
call g:Xsetlist([], 'a', {'title' : 'Sample'})
|
||||
let s = g:Xsetlist([], 'a', {'title' : 'Sample'})
|
||||
call assert_equal(0, s)
|
||||
let d = g:Xgetlist({"title":1})
|
||||
call assert_equal('Sample', d.title)
|
||||
|
||||
@@ -1774,7 +1775,8 @@ func Xproperty_tests(cchar)
|
||||
endif
|
||||
|
||||
" Context related tests
|
||||
call g:Xsetlist([], 'a', {'context':[1,2,3]})
|
||||
let s = g:Xsetlist([], 'a', {'context':[1,2,3]})
|
||||
call assert_equal(0, s)
|
||||
call test_garbagecollect_now()
|
||||
let d = g:Xgetlist({'context':1})
|
||||
call assert_equal([1,2,3], d.context)
|
||||
@@ -1839,8 +1841,9 @@ func Xproperty_tests(cchar)
|
||||
" Test for setting/getting items
|
||||
Xexpr ""
|
||||
let qfprev = g:Xgetlist({'nr':0})
|
||||
call g:Xsetlist([], ' ', {'title':'Green',
|
||||
let s = g:Xsetlist([], ' ', {'title':'Green',
|
||||
\ 'items' : [{'filename':'F1', 'lnum':10}]})
|
||||
call assert_equal(0, s)
|
||||
let qfcur = g:Xgetlist({'nr':0})
|
||||
call assert_true(qfcur.nr == qfprev.nr + 1)
|
||||
let l = g:Xgetlist({'items':1})
|
||||
@@ -2187,18 +2190,6 @@ func Test_bufoverflow()
|
||||
set efm&vim
|
||||
endfunc
|
||||
|
||||
func Test_cclose_from_copen()
|
||||
augroup QF_Test
|
||||
au!
|
||||
au FileType qf :cclose
|
||||
augroup END
|
||||
copen
|
||||
augroup QF_Test
|
||||
au!
|
||||
augroup END
|
||||
augroup! QF_Test
|
||||
endfunc
|
||||
|
||||
" Tests for getting the quickfix stack size
|
||||
func XsizeTests(cchar)
|
||||
call s:setup_commands(a:cchar)
|
||||
@@ -2227,3 +2218,48 @@ func Test_Qf_Size()
|
||||
call XsizeTests('c')
|
||||
call XsizeTests('l')
|
||||
endfunc
|
||||
|
||||
func Test_cclose_from_copen()
|
||||
augroup QF_Test
|
||||
au!
|
||||
au FileType qf :call assert_fails(':cclose', 'E788')
|
||||
augroup END
|
||||
copen
|
||||
augroup QF_Test
|
||||
au!
|
||||
augroup END
|
||||
augroup! QF_Test
|
||||
endfunc
|
||||
|
||||
func Test_cclose_in_autocmd()
|
||||
" Problem is only triggered if "starting" is zero, so that the OptionsSet
|
||||
" event will be triggered.
|
||||
call test_override('starting', 1)
|
||||
augroup QF_Test
|
||||
au!
|
||||
au FileType qf :call assert_fails(':cclose', 'E788')
|
||||
augroup END
|
||||
copen
|
||||
augroup QF_Test
|
||||
au!
|
||||
augroup END
|
||||
augroup! QF_Test
|
||||
call test_override('starting', 0)
|
||||
endfunc
|
||||
|
||||
func Test_resize_from_copen()
|
||||
augroup QF_Test
|
||||
au!
|
||||
au FileType qf resize 5
|
||||
augroup END
|
||||
try
|
||||
" This should succeed without any exception. No other buffers are
|
||||
" involved in the autocmd.
|
||||
copen
|
||||
finally
|
||||
augroup QF_Test
|
||||
au!
|
||||
augroup END
|
||||
augroup! QF_Test
|
||||
endtry
|
||||
endfunc
|
||||
|
||||
22
src/testdir/test_sha256.vim
Normal file
22
src/testdir/test_sha256.vim
Normal file
@@ -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
|
||||
@@ -474,26 +473,50 @@ func Test_conceal()
|
||||
|
||||
set conceallevel=0
|
||||
call assert_equal('123456 ', ScreenLines(2, 7)[0])
|
||||
call assert_equal([[0, ''], [0, ''], [0, ''], [0, ''], [0, ''], [0, '']], map(range(1, 6), 'synconcealed(2, v:val)[0:1]'))
|
||||
call assert_equal([[0, '', 0], [0, '', 0], [0, '', 0], [0, '', 0], [0, '', 0], [0, '', 0]], map(range(1, 6), 'synconcealed(2, v:val)'))
|
||||
|
||||
set conceallevel=1
|
||||
call assert_equal('1X 6 ', ScreenLines(2, 7)[0])
|
||||
call assert_equal([[0, ''], [1, 'X'], [1, 'X'], [1, ' '], [1, ' '], [0, '']], map(range(1, 6), 'synconcealed(2, v:val)[0:1]'))
|
||||
call assert_equal([[0, '', 0], [1, 'X', 1], [1, 'X', 1], [1, ' ', 2], [1, ' ', 2], [0, '', 0]], map(range(1, 6), 'synconcealed(2, v:val)'))
|
||||
|
||||
set conceallevel=1
|
||||
set listchars=conceal:Y
|
||||
call assert_equal([[0, ''], [1, 'X'], [1, 'X'], [1, 'Y'], [1, 'Y'], [0, '']], map(range(1, 6), 'synconcealed(2, v:val)[0:1]'))
|
||||
call assert_equal([[0, '', 0], [1, 'X', 1], [1, 'X', 1], [1, 'Y', 2], [1, 'Y', 2], [0, '', 0]], map(range(1, 6), 'synconcealed(2, v:val)'))
|
||||
call assert_equal('1XY6 ', ScreenLines(2, 7)[0])
|
||||
|
||||
set conceallevel=2
|
||||
call assert_match('1X6 ', ScreenLines(2, 7)[0])
|
||||
call assert_equal([[0, ''], [1, 'X'], [1, 'X'], [1, ''], [1, ''], [0, '']], map(range(1, 6), 'synconcealed(2, v:val)[0:1]'))
|
||||
call assert_equal([[0, '', 0], [1, 'X', 1], [1, 'X', 1], [1, '', 2], [1, '', 2], [0, '', 0]], map(range(1, 6), 'synconcealed(2, v:val)'))
|
||||
|
||||
set conceallevel=3
|
||||
call assert_match('16 ', ScreenLines(2, 7)[0])
|
||||
call assert_equal([[0, ''], [1, ''], [1, ''], [1, ''], [1, ''], [0, '']], map(range(1, 6), 'synconcealed(2, v:val)[0:1]'))
|
||||
call assert_equal([[0, '', 0], [1, '', 1], [1, '', 1], [1, '', 2], [1, '', 2], [0, '', 0]], map(range(1, 6), 'synconcealed(2, v:val)'))
|
||||
|
||||
syn clear
|
||||
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
|
||||
|
||||
@@ -172,5 +172,21 @@ func Test_stop_all_in_callback()
|
||||
call assert_equal(0, len(info))
|
||||
endfunc
|
||||
|
||||
func FeedkeysCb(timer)
|
||||
call feedkeys("hello\<CR>", 'nt')
|
||||
endfunc
|
||||
|
||||
func InputCb(timer)
|
||||
call timer_start(10, 'FeedkeysCb')
|
||||
let g:val = input('?')
|
||||
call Resume()
|
||||
endfunc
|
||||
|
||||
func Test_input_in_timer()
|
||||
let g:val = ''
|
||||
call timer_start(10, 'InputCb')
|
||||
call Standby(1000)
|
||||
call assert_equal('hello', g:val)
|
||||
endfunc
|
||||
|
||||
" vim: shiftwidth=2 sts=2 expandtab
|
||||
|
||||
95
src/testdir/test_utf8_comparisons.vim
Normal file
95
src/testdir/test_utf8_comparisons.vim
Normal file
@@ -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
|
||||
@@ -1379,6 +1379,11 @@ func Test_endfunction_trailing()
|
||||
delfunc Xtest
|
||||
unlet done
|
||||
|
||||
" trailing line break
|
||||
exe "func Xtest()\necho 'hello'\nendfunc\n"
|
||||
call assert_true(exists('*Xtest'))
|
||||
delfunc Xtest
|
||||
|
||||
set verbose=1
|
||||
exe "func Xtest()\necho 'hello'\nendfunc \" garbage"
|
||||
call assert_notmatch('W22:', split(execute('1messages'), "\n")[0])
|
||||
@@ -1390,6 +1395,11 @@ func Test_endfunction_trailing()
|
||||
call assert_true(exists('*Xtest'))
|
||||
delfunc Xtest
|
||||
set verbose=0
|
||||
|
||||
function Foo()
|
||||
echo 'hello'
|
||||
endfunction | echo 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
|
||||
delfunc Foo
|
||||
endfunc
|
||||
|
||||
func Test_delfunction_force()
|
||||
|
||||
@@ -318,6 +318,50 @@ func Test_window_width()
|
||||
bw Xa Xb Xc
|
||||
endfunc
|
||||
|
||||
func Test_equalalways_on_close()
|
||||
set equalalways
|
||||
vsplit
|
||||
windo split
|
||||
split
|
||||
wincmd J
|
||||
" now we have a frame top-left with two windows, a frame top-right with two
|
||||
" windows and a frame at the bottom, full-width.
|
||||
let height_1 = winheight(1)
|
||||
let height_2 = winheight(2)
|
||||
let height_3 = winheight(3)
|
||||
let height_4 = winheight(4)
|
||||
" closing the bottom window causes all windows to be resized.
|
||||
close
|
||||
call assert_notequal(height_1, winheight(1))
|
||||
call assert_notequal(height_2, winheight(2))
|
||||
call assert_notequal(height_3, winheight(3))
|
||||
call assert_notequal(height_4, winheight(4))
|
||||
call assert_equal(winheight(1), winheight(3))
|
||||
call assert_equal(winheight(2), winheight(4))
|
||||
|
||||
1wincmd w
|
||||
split
|
||||
4wincmd w
|
||||
resize + 5
|
||||
" left column has three windows, equalized heights.
|
||||
" right column has two windows, top one a bit higher
|
||||
let height_1 = winheight(1)
|
||||
let height_2 = winheight(2)
|
||||
let height_4 = winheight(4)
|
||||
let height_5 = winheight(5)
|
||||
3wincmd w
|
||||
" closing window in left column equalizes heights in left column but not in
|
||||
" the right column
|
||||
close
|
||||
call assert_notequal(height_1, winheight(1))
|
||||
call assert_notequal(height_2, winheight(2))
|
||||
call assert_equal(height_4, winheight(3))
|
||||
call assert_equal(height_5, winheight(4))
|
||||
|
||||
only
|
||||
set equalalways&
|
||||
endfunc
|
||||
|
||||
func Test_window_jump_tag()
|
||||
help
|
||||
/iccf
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1780,6 +1780,7 @@ theend:
|
||||
ex_function(exarg_T *eap)
|
||||
{
|
||||
char_u *theline;
|
||||
char_u *line_to_free = NULL;
|
||||
int j;
|
||||
int c;
|
||||
int saved_did_emsg;
|
||||
@@ -2093,10 +2094,15 @@ ex_function(exarg_T *eap)
|
||||
line_arg = p + 1;
|
||||
}
|
||||
}
|
||||
else if (eap->getline == NULL)
|
||||
theline = getcmdline(':', 0L, indent);
|
||||
else
|
||||
theline = eap->getline(':', eap->cookie, indent);
|
||||
{
|
||||
vim_free(line_to_free);
|
||||
if (eap->getline == NULL)
|
||||
theline = getcmdline(':', 0L, indent);
|
||||
else
|
||||
theline = eap->getline(':', eap->cookie, indent);
|
||||
line_to_free = theline;
|
||||
}
|
||||
if (KeyTyped)
|
||||
lines_left = Rows - 1;
|
||||
if (theline == NULL)
|
||||
@@ -2130,18 +2136,29 @@ ex_function(exarg_T *eap)
|
||||
/* Check for "endfunction". */
|
||||
if (checkforcmd(&p, "endfunction", 4) && nesting-- == 0)
|
||||
{
|
||||
char_u *nextcmd = NULL;
|
||||
|
||||
if (*p == '|')
|
||||
/* Another command follows. */
|
||||
eap->nextcmd = vim_strsave(p + 1);
|
||||
nextcmd = p + 1;
|
||||
else if (line_arg != NULL && *skipwhite(line_arg) != NUL)
|
||||
/* Another command follows. */
|
||||
eap->nextcmd = line_arg;
|
||||
nextcmd = line_arg;
|
||||
else if (*p != NUL && *p != '"' && p_verbose > 0)
|
||||
give_warning2(
|
||||
(char_u *)_("W22: Text found after :endfunction: %s"),
|
||||
p, TRUE);
|
||||
if (line_arg == NULL)
|
||||
vim_free(theline);
|
||||
if (nextcmd != NULL)
|
||||
{
|
||||
/* Another command follows. If the line came from "eap" we
|
||||
* can simply point into it, otherwise we need to change
|
||||
* "eap->cmdlinep". */
|
||||
eap->nextcmd = nextcmd;
|
||||
if (line_to_free != NULL)
|
||||
{
|
||||
vim_free(*eap->cmdlinep);
|
||||
*eap->cmdlinep = line_to_free;
|
||||
line_to_free = NULL;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2212,24 +2229,15 @@ ex_function(exarg_T *eap)
|
||||
|
||||
/* Add the line to the function. */
|
||||
if (ga_grow(&newlines, 1 + sourcing_lnum_off) == FAIL)
|
||||
{
|
||||
if (line_arg == NULL)
|
||||
vim_free(theline);
|
||||
goto erret;
|
||||
}
|
||||
|
||||
/* Copy the line to newly allocated memory. get_one_sourceline()
|
||||
* allocates 250 bytes per line, this saves 80% on average. The cost
|
||||
* is an extra alloc/free. */
|
||||
p = vim_strsave(theline);
|
||||
if (p != NULL)
|
||||
{
|
||||
if (line_arg == NULL)
|
||||
vim_free(theline);
|
||||
theline = p;
|
||||
}
|
||||
|
||||
((char_u **)(newlines.ga_data))[newlines.ga_len++] = theline;
|
||||
if (p == NULL)
|
||||
goto erret;
|
||||
((char_u **)(newlines.ga_data))[newlines.ga_len++] = p;
|
||||
|
||||
/* Add NULL lines for continuation lines, so that the line count is
|
||||
* equal to the index in the growarray. */
|
||||
@@ -2428,6 +2436,7 @@ errret_2:
|
||||
ga_clear_strings(&newlines);
|
||||
ret_free:
|
||||
vim_free(skip_until);
|
||||
vim_free(line_to_free);
|
||||
vim_free(fudi.fd_newkey);
|
||||
vim_free(name);
|
||||
did_emsg |= saved_did_emsg;
|
||||
|
||||
@@ -764,6 +764,56 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
688,
|
||||
/**/
|
||||
687,
|
||||
/**/
|
||||
686,
|
||||
/**/
|
||||
685,
|
||||
/**/
|
||||
684,
|
||||
/**/
|
||||
683,
|
||||
/**/
|
||||
682,
|
||||
/**/
|
||||
681,
|
||||
/**/
|
||||
680,
|
||||
/**/
|
||||
679,
|
||||
/**/
|
||||
678,
|
||||
/**/
|
||||
677,
|
||||
/**/
|
||||
676,
|
||||
/**/
|
||||
675,
|
||||
/**/
|
||||
674,
|
||||
/**/
|
||||
673,
|
||||
/**/
|
||||
672,
|
||||
/**/
|
||||
671,
|
||||
/**/
|
||||
670,
|
||||
/**/
|
||||
669,
|
||||
/**/
|
||||
668,
|
||||
/**/
|
||||
667,
|
||||
/**/
|
||||
666,
|
||||
/**/
|
||||
665,
|
||||
/**/
|
||||
664,
|
||||
/**/
|
||||
663,
|
||||
/**/
|
||||
|
||||
@@ -2282,6 +2282,7 @@ win_close(win_T *win, int free_buf)
|
||||
int dir;
|
||||
int help_window = FALSE;
|
||||
tabpage_T *prev_curtab = curtab;
|
||||
frame_T *win_frame = win->w_frame->fr_parent;
|
||||
|
||||
if (last_window())
|
||||
{
|
||||
@@ -2459,7 +2460,9 @@ win_close(win_T *win, int free_buf)
|
||||
check_cursor();
|
||||
}
|
||||
if (p_ea && (*p_ead == 'b' || *p_ead == dir))
|
||||
win_equal(curwin, TRUE, dir);
|
||||
/* If the frame of the closed window contains the new current window,
|
||||
* only resize that frame. Otherwise resize all windows. */
|
||||
win_equal(curwin, curwin->w_frame->fr_parent == win_frame, dir);
|
||||
else
|
||||
win_comp_pos();
|
||||
if (close_curwin)
|
||||
|
||||
Reference in New Issue
Block a user