Merge pull request #14403 from seandewar/vim-8.2.1933

vim-patch:8.2.{0174,1933,1935,1946,2286,2287}
This commit is contained in:
Jan Edmund Lazo
2021-05-09 17:08:21 -04:00
committed by GitHub
20 changed files with 551 additions and 22 deletions

View File

@@ -1771,7 +1771,7 @@ Vim has a sorting function and a sorting command. The sorting function can be
found here: |sort()|, |uniq()|. found here: |sort()|, |uniq()|.
*:sor* *:sort* *:sor* *:sort*
:[range]sor[t][!] [b][f][i][n][o][r][u][x] [/{pattern}/] :[range]sor[t][!] [b][f][i][l][n][o][r][u][x] [/{pattern}/]
Sort lines in [range]. When no range is given all Sort lines in [range]. When no range is given all
lines are sorted. lines are sorted.
@@ -1779,6 +1779,16 @@ found here: |sort()|, |uniq()|.
With [i] case is ignored. With [i] case is ignored.
With [l] sort uses the current collation locale.
Implementation details: strcoll() is used to compare
strings. See |:language| to check or set the collation
locale. Example: >
:language collate en_US.UTF-8
:%sort l
< |v:collate| can also used to check the current locale.
Sorting using the locale typically ignores case.
This does not work properly on Mac.
Options [n][f][x][o][b] are mutually exclusive. Options [n][f][x][o][b] are mutually exclusive.
With [n] sorting is done on the first decimal number With [n] sorting is done on the first decimal number
@@ -1847,8 +1857,7 @@ found here: |sort()|, |uniq()|.
Note that using `:sort` with `:global` doesn't sort the matching lines, it's Note that using `:sort` with `:global` doesn't sort the matching lines, it's
quite useless. quite useless.
The details about sorting depend on the library function used. There is no `:sort` does not use the current locale unless the l flag is used.
guarantee that sorting obeys the current locale. You will have to try it out.
Vim does do a "stable" sort. Vim does do a "stable" sort.
The sorting can be interrupted, but if you interrupt it too late in the The sorting can be interrupted, but if you interrupt it too late in the

View File

@@ -1508,6 +1508,15 @@ v:cmdarg This variable is used for two purposes:
the argument for the ":hardcopy" command. This can be used the argument for the ":hardcopy" command. This can be used
in 'printexpr'. in 'printexpr'.
*v:collate* *collate-variable*
v:collate The current locale setting for collation order of the runtime
environment. This allows Vim scripts to be aware of the
current locale encoding. Technical: it's the value of
LC_COLLATE. When not using a locale the value is "C".
This variable can not be set directly, use the |:language|
command.
See |multi-lang|.
*v:cmdbang* *cmdbang-variable* *v:cmdbang* *cmdbang-variable*
v:cmdbang Set like v:cmdarg for a file read/write command. When a "!" v:cmdbang Set like v:cmdarg for a file read/write command. When a "!"
was used the value is 1, otherwise it is 0. Note that this was used the value is 1, otherwise it is 0. Note that this
@@ -8007,6 +8016,23 @@ sort({list} [, {func} [, {dict}]]) *sort()* *E702*
When {func} is given and it is '1' or 'i' then case is When {func} is given and it is '1' or 'i' then case is
ignored. ignored.
When {func} is given and it is 'l' then the current collation
locale is used for ordering. Implementation details: strcoll()
is used to compare strings. See |:language| check or set the
collation locale. |v:collate| can also be used to check the
current locale. Sorting using the locale typically ignores
case. Example: >
" ö is sorted similarly to o with English locale.
:language collate en_US.UTF8
:echo sort(['n', 'o', 'O', 'ö', 'p', 'z'], 'l')
< ['n', 'o', 'O', 'ö', 'p', 'z'] ~
>
" ö is sorted after z with Swedish locale.
:language collate sv_SE.UTF8
:echo sort(['n', 'o', 'O', 'ö', 'p', 'z'], 'l')
< ['n', 'o', 'O', 'p', 'z', 'ö'] ~
This does not work properly on Mac.
When {func} is given and it is 'n' then all items will be When {func} is given and it is 'n' then all items will be
sorted numerical (Implementation detail: this uses the sorted numerical (Implementation detail: this uses the
strtod() function to parse numbers, Strings, Lists, Dicts and strtod() function to parse numbers, Strings, Lists, Dicts and

View File

@@ -31,6 +31,7 @@ use of "-" and "_".
:lan[guage] mes[sages] :lan[guage] mes[sages]
:lan[guage] cty[pe] :lan[guage] cty[pe]
:lan[guage] tim[e] :lan[guage] tim[e]
:lan[guage] col[late]
Print the current language (aka locale). Print the current language (aka locale).
With the "messages" argument the language used for With the "messages" argument the language used for
messages is printed. Technical: LC_MESSAGES. messages is printed. Technical: LC_MESSAGES.
@@ -38,15 +39,19 @@ use of "-" and "_".
character encoding is printed. Technical: LC_CTYPE. character encoding is printed. Technical: LC_CTYPE.
With the "time" argument the language used for With the "time" argument the language used for
strftime() is printed. Technical: LC_TIME. strftime() is printed. Technical: LC_TIME.
With the "collate" argument the language used for
collation order is printed. Technical: LC_COLLATE.
Without argument all parts of the locale are printed Without argument all parts of the locale are printed
(this is system dependent). (this is system dependent).
The current language can also be obtained with the The current language can also be obtained with the
|v:lang|, |v:ctype| and |v:lc_time| variables. |v:lang|, |v:ctype|, |v:collate| and |v:lc_time|
variables.
:lan[guage] {name} :lan[guage] {name}
:lan[guage] mes[sages] {name} :lan[guage] mes[sages] {name}
:lan[guage] cty[pe] {name} :lan[guage] cty[pe] {name}
:lan[guage] tim[e] {name} :lan[guage] tim[e] {name}
:lan[guage] col[late] {name}
Set the current language (aka locale) to {name}. Set the current language (aka locale) to {name}.
The locale {name} must be a valid locale on your The locale {name} must be a valid locale on your
system. Some systems accept aliases like "en" or system. Some systems accept aliases like "en" or
@@ -66,7 +71,10 @@ use of "-" and "_".
With the "time" argument the language used for time With the "time" argument the language used for time
and date messages is set. This affects strftime(). and date messages is set. This affects strftime().
This sets $LC_TIME. This sets $LC_TIME.
Without an argument both are set, and additionally With the "collate" argument the language used for the
collation order is set. This affects sorting of
characters. This sets $LC_COLLATE.
Without an argument all are set, and additionally
$LANG is set. $LANG is set.
The LC_NUMERIC value will always be set to "C" so The LC_NUMERIC value will always be set to "C" so
that floating point numbers use '.' as the decimal that floating point numbers use '.' as the decimal

View File

@@ -228,6 +228,7 @@ static struct vimvar {
VV(VV_EVENT, "event", VAR_DICT, VV_RO), VV(VV_EVENT, "event", VAR_DICT, VV_RO),
VV(VV_ECHOSPACE, "echospace", VAR_NUMBER, VV_RO), VV(VV_ECHOSPACE, "echospace", VAR_NUMBER, VV_RO),
VV(VV_ARGV, "argv", VAR_LIST, VV_RO), VV(VV_ARGV, "argv", VAR_LIST, VV_RO),
VV(VV_COLLATE, "collate", VAR_STRING, VV_RO),
VV(VV_EXITING, "exiting", VAR_NUMBER, VV_RO), VV(VV_EXITING, "exiting", VAR_NUMBER, VV_RO),
// Neovim // Neovim
VV(VV_STDERR, "stderr", VAR_NUMBER, VV_RO), VV(VV_STDERR, "stderr", VAR_NUMBER, VV_RO),

View File

@@ -157,6 +157,7 @@ typedef enum {
VV_EVENT, VV_EVENT,
VV_ECHOSPACE, VV_ECHOSPACE,
VV_ARGV, VV_ARGV,
VV_COLLATE,
VV_EXITING, VV_EXITING,
// Neovim // Neovim
VV_STDERR, VV_STDERR,

View File

@@ -9154,6 +9154,7 @@ static void f_sockconnect(typval_T *argvars, typval_T *rettv, FunPtr fptr)
/// struct storing information about current sort /// struct storing information about current sort
typedef struct { typedef struct {
int item_compare_ic; int item_compare_ic;
bool item_compare_lc;
bool item_compare_numeric; bool item_compare_numeric;
bool item_compare_numbers; bool item_compare_numbers;
bool item_compare_float; bool item_compare_float;
@@ -9228,10 +9229,10 @@ static int item_compare(const void *s1, const void *s2, bool keep_zero)
p2 = ""; p2 = "";
} }
if (!sortinfo->item_compare_numeric) { if (!sortinfo->item_compare_numeric) {
if (sortinfo->item_compare_ic) { if (sortinfo->item_compare_lc) {
res = STRICMP(p1, p2); res = strcoll(p1, p2);
} else { } else {
res = STRCMP(p1, p2); res = sortinfo->item_compare_ic ? STRICMP(p1, p2): STRCMP(p1, p2);
} }
} else { } else {
double n1, n2; double n1, n2;
@@ -9366,6 +9367,7 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort)
} }
info.item_compare_ic = false; info.item_compare_ic = false;
info.item_compare_lc = false;
info.item_compare_numeric = false; info.item_compare_numeric = false;
info.item_compare_numbers = false; info.item_compare_numbers = false;
info.item_compare_float = false; info.item_compare_float = false;
@@ -9410,6 +9412,9 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort)
} else if (strcmp(info.item_compare_func, "i") == 0) { } else if (strcmp(info.item_compare_func, "i") == 0) {
info.item_compare_func = NULL; info.item_compare_func = NULL;
info.item_compare_ic = true; info.item_compare_ic = true;
} else if (strcmp(info.item_compare_func, "l") == 0) {
info.item_compare_func = NULL;
info.item_compare_lc = true;
} }
} }
} }

View File

@@ -358,6 +358,7 @@ static int linelen(int *has_tab)
static char_u *sortbuf1; static char_u *sortbuf1;
static char_u *sortbuf2; static char_u *sortbuf2;
static int sort_lc; ///< sort using locale
static int sort_ic; ///< ignore case static int sort_ic; ///< ignore case
static int sort_nr; ///< sort on number static int sort_nr; ///< sort on number
static int sort_rx; ///< sort on regex instead of skipping it static int sort_rx; ///< sort on regex instead of skipping it
@@ -381,6 +382,13 @@ typedef struct {
} st_u; } st_u;
} sorti_T; } sorti_T;
static int string_compare(const void *s1, const void *s2) FUNC_ATTR_NONNULL_ALL
{
if (sort_lc) {
return strcoll((char *)s1, (char *)s2);
}
return sort_ic ? STRICMP(s1, s2) : STRCMP(s1, s2);
}
static int sort_compare(const void *s1, const void *s2) static int sort_compare(const void *s1, const void *s2)
{ {
@@ -424,8 +432,7 @@ static int sort_compare(const void *s1, const void *s2)
l2.st_u.line.end_col_nr - l2.st_u.line.start_col_nr + 1); l2.st_u.line.end_col_nr - l2.st_u.line.start_col_nr + 1);
sortbuf2[l2.st_u.line.end_col_nr - l2.st_u.line.start_col_nr] = NUL; sortbuf2[l2.st_u.line.end_col_nr - l2.st_u.line.start_col_nr] = NUL;
result = sort_ic ? STRICMP(sortbuf1, sortbuf2) result = string_compare(sortbuf1, sortbuf2);
: STRCMP(sortbuf1, sortbuf2);
} }
/* If two lines have the same value, preserve the original line order. */ /* If two lines have the same value, preserve the original line order. */
@@ -466,7 +473,7 @@ void ex_sort(exarg_T *eap)
regmatch.regprog = NULL; regmatch.regprog = NULL;
sorti_T *nrs = xmalloc(count * sizeof(sorti_T)); sorti_T *nrs = xmalloc(count * sizeof(sorti_T));
sort_abort = sort_ic = sort_rx = sort_nr = sort_flt = 0; sort_abort = sort_ic = sort_lc = sort_rx = sort_nr = sort_flt = 0;
size_t format_found = 0; size_t format_found = 0;
bool change_occurred = false; // Buffer contents changed. bool change_occurred = false; // Buffer contents changed.
@@ -474,6 +481,8 @@ void ex_sort(exarg_T *eap)
if (ascii_iswhite(*p)) { if (ascii_iswhite(*p)) {
} else if (*p == 'i') { } else if (*p == 'i') {
sort_ic = true; sort_ic = true;
} else if (*p == 'l') {
sort_lc = true;
} else if (*p == 'r') { } else if (*p == 'r') {
sort_rx = true; sort_rx = true;
} else if (*p == 'n') { } else if (*p == 'n') {
@@ -645,8 +654,7 @@ void ex_sort(exarg_T *eap)
s = ml_get(get_lnum); s = ml_get(get_lnum);
size_t bytelen = STRLEN(s) + 1; // include EOL in bytelen size_t bytelen = STRLEN(s) + 1; // include EOL in bytelen
old_count += bytelen; old_count += bytelen;
if (!unique || i == 0 if (!unique || i == 0 || string_compare(s, sortbuf1) != 0) {
|| (sort_ic ? STRICMP(s, sortbuf1) : STRCMP(s, sortbuf1)) != 0) {
// Copy the line into a buffer, it may become invalid in // Copy the line into a buffer, it may become invalid in
// ml_append(). And it's needed for "unique". // ml_append(). And it's needed for "unique".
STRCPY(sortbuf1, s); STRCPY(sortbuf1, s);

View File

@@ -3621,6 +3621,14 @@ void set_lang_var(void)
loc = get_locale_val(LC_TIME); loc = get_locale_val(LC_TIME);
# endif # endif
set_vim_var_string(VV_LC_TIME, loc, -1); set_vim_var_string(VV_LC_TIME, loc, -1);
# ifdef HAVE_GET_LOCALE_VAL
loc = get_locale_val(LC_COLLATE);
# else
// setlocale() not supported: use the default value
loc = "C";
# endif
set_vim_var_string(VV_COLLATE, loc, -1);
} }
#ifdef HAVE_WORKING_LIBINTL #ifdef HAVE_WORKING_LIBINTL
@@ -3661,6 +3669,10 @@ void ex_language(exarg_T *eap)
what = LC_TIME; what = LC_TIME;
name = skipwhite(p); name = skipwhite(p);
whatstr = "time "; whatstr = "time ";
} else if (STRNICMP(eap->arg, "collate", p - eap->arg) == 0) {
what = LC_COLLATE;
name = skipwhite(p);
whatstr = "collate ";
} }
} }
@@ -3705,7 +3717,7 @@ void ex_language(exarg_T *eap)
// Reset $LC_ALL, otherwise it would overrule everything. // Reset $LC_ALL, otherwise it would overrule everything.
os_setenv("LC_ALL", "", 1); os_setenv("LC_ALL", "", 1);
if (what != LC_TIME) { if (what != LC_TIME && what != LC_COLLATE) {
// Tell gettext() what to translate to. It apparently doesn't // Tell gettext() what to translate to. It apparently doesn't
// use the currently effective locale. // use the currently effective locale.
if (what == LC_ALL) { if (what == LC_ALL) {
@@ -3720,7 +3732,7 @@ void ex_language(exarg_T *eap)
} }
} }
// Set v:lang, v:lc_time and v:ctype to the final result. // Set v:lang, v:lc_time, v:collate and v:ctype to the final result.
set_lang_var(); set_lang_var();
maketitle(); maketitle();
} }
@@ -3805,12 +3817,15 @@ char_u *get_lang_arg(expand_T *xp, int idx)
if (idx == 2) { if (idx == 2) {
return (char_u *)"time"; return (char_u *)"time";
} }
if (idx == 3) {
return (char_u *)"collate";
}
init_locales(); init_locales();
if (locales == NULL) { if (locales == NULL) {
return NULL; return NULL;
} }
return locales[idx - 3]; return locales[idx - 4];
} }
/// Function given to ExpandGeneric() to obtain the available locales. /// Function given to ExpandGeneric() to obtain the available locales.

View File

@@ -3642,7 +3642,8 @@ const char * set_one_cmd_context(
} else { } else {
if (strncmp(arg, "messages", p - arg) == 0 if (strncmp(arg, "messages", p - arg) == 0
|| strncmp(arg, "ctype", p - arg) == 0 || strncmp(arg, "ctype", p - arg) == 0
|| strncmp(arg, "time", p - arg) == 0) { || strncmp(arg, "time", p - arg) == 0
|| strncmp(arg, "collate", p - arg) == 0) {
xp->xp_context = EXPAND_LOCALES; xp->xp_context = EXPAND_LOCALES;
xp->xp_pattern = skipwhite((const char_u *)p); xp->xp_pattern = skipwhite((const char_u *)p);
} else { } else {

View File

@@ -615,10 +615,20 @@ func Test_cmdline_complete_bang()
endfunc endfunc
funct Test_cmdline_complete_languages() funct Test_cmdline_complete_languages()
let lang = substitute(execute('language time'), '.*"\(.*\)"$', '\1', '')
call assert_equal(lang, v:lc_time)
let lang = substitute(execute('language ctype'), '.*"\(.*\)"$', '\1', '')
call assert_equal(lang, v:ctype)
let lang = substitute(execute('language collate'), '.*"\(.*\)"$', '\1', '')
call assert_equal(lang, v:collate)
let lang = substitute(execute('language messages'), '.*"\(.*\)"$', '\1', '') let lang = substitute(execute('language messages'), '.*"\(.*\)"$', '\1', '')
call assert_equal(lang, v:lang)
call feedkeys(":language \<c-a>\<c-b>\"\<cr>", 'tx') call feedkeys(":language \<c-a>\<c-b>\"\<cr>", 'tx')
call assert_match('^"language .*\<ctype\>.*\<messages\>.*\<time\>', @:) call assert_match('^"language .*\<collate\>.*\<ctype\>.*\<messages\>.*\<time\>', @:)
if has('unix') if has('unix')
" TODO: these tests don't work on Windows. lang appears to be 'C' " TODO: these tests don't work on Windows. lang appears to be 'C'
@@ -633,6 +643,9 @@ funct Test_cmdline_complete_languages()
call feedkeys(":language time \<c-a>\<c-b>\"\<cr>", 'tx') call feedkeys(":language time \<c-a>\<c-b>\"\<cr>", 'tx')
call assert_match('^"language .*\<' . lang . '\>', @:) call assert_match('^"language .*\<' . lang . '\>', @:)
call feedkeys(":language collate \<c-a>\<c-b>\"\<cr>", 'tx')
call assert_match('^"language .*\<' . lang . '\>', @:)
endif endif
endfunc endfunc

View File

@@ -54,6 +54,132 @@ func Test_buffers_lastused()
bwipeout bufc bwipeout bufc
endfunc endfunc
" Test for the :copy command
func Test_copy()
new
call setline(1, ['L1', 'L2', 'L3', 'L4'])
" copy lines in a range to inside the range
1,3copy 2
call assert_equal(['L1', 'L2', 'L1', 'L2', 'L3', 'L3', 'L4'], getline(1, 7))
close!
endfunc
" Test for the :file command
func Test_file_cmd()
call assert_fails('3file', 'E474:')
call assert_fails('0,0file', 'E474:')
call assert_fails('0file abc', 'E474:')
endfunc
" Test for the :drop command
func Test_drop_cmd()
call writefile(['L1', 'L2'], 'Xfile')
enew | only
drop Xfile
call assert_equal('L2', getline(2))
" Test for switching to an existing window
below new
drop Xfile
call assert_equal(1, winnr())
" Test for splitting the current window
enew | only
set modified
drop Xfile
call assert_equal(2, winnr('$'))
" Check for setting the argument list
call assert_equal(['Xfile'], argv())
enew | only!
call delete('Xfile')
endfunc
" Test for the :append command
func Test_append_cmd()
new
call setline(1, [' L1'])
call feedkeys(":append\<CR> L2\<CR> L3\<CR>.\<CR>", 'xt')
call assert_equal([' L1', ' L2', ' L3'], getline(1, '$'))
%delete _
" append after a specific line
call setline(1, [' L1', ' L2', ' L3'])
call feedkeys(":2append\<CR> L4\<CR> L5\<CR>.\<CR>", 'xt')
call assert_equal([' L1', ' L2', ' L4', ' L5', ' L3'], getline(1, '$'))
%delete _
" append with toggling 'autoindent'
call setline(1, [' L1'])
call feedkeys(":append!\<CR> L2\<CR> L3\<CR>.\<CR>", 'xt')
call assert_equal([' L1', ' L2', ' L3'], getline(1, '$'))
call assert_false(&autoindent)
%delete _
" append with 'autoindent' set and toggling 'autoindent'
set autoindent
call setline(1, [' L1'])
call feedkeys(":append!\<CR> L2\<CR> L3\<CR>.\<CR>", 'xt')
call assert_equal([' L1', ' L2', ' L3'], getline(1, '$'))
call assert_true(&autoindent)
set autoindent&
close!
endfunc
" Test for the :insert command
func Test_insert_cmd()
set noautoindent " test assumes noautoindent, but it's on by default in Nvim
new
call setline(1, [' L1'])
call feedkeys(":insert\<CR> L2\<CR> L3\<CR>.\<CR>", 'xt')
call assert_equal([' L2', ' L3', ' L1'], getline(1, '$'))
%delete _
" insert before a specific line
call setline(1, [' L1', ' L2', ' L3'])
call feedkeys(":2insert\<CR> L4\<CR> L5\<CR>.\<CR>", 'xt')
call assert_equal([' L1', ' L4', ' L5', ' L2', ' L3'], getline(1, '$'))
%delete _
" insert with toggling 'autoindent'
call setline(1, [' L1'])
call feedkeys(":insert!\<CR> L2\<CR> L3\<CR>.\<CR>", 'xt')
call assert_equal([' L2', ' L3', ' L1'], getline(1, '$'))
call assert_false(&autoindent)
%delete _
" insert with 'autoindent' set and toggling 'autoindent'
set autoindent
call setline(1, [' L1'])
call feedkeys(":insert!\<CR> L2\<CR> L3\<CR>.\<CR>", 'xt')
call assert_equal([' L2', ' L3', ' L1'], getline(1, '$'))
call assert_true(&autoindent)
set autoindent&
close!
endfunc
" Test for the :change command
func Test_change_cmd()
set noautoindent " test assumes noautoindent, but it's on by default in Nvim
new
call setline(1, [' L1', 'L2', 'L3'])
call feedkeys(":change\<CR> L4\<CR> L5\<CR>.\<CR>", 'xt')
call assert_equal([' L4', ' L5', 'L2', 'L3'], getline(1, '$'))
%delete _
" change a specific line
call setline(1, [' L1', ' L2', ' L3'])
call feedkeys(":2change\<CR> L4\<CR> L5\<CR>.\<CR>", 'xt')
call assert_equal([' L1', ' L4', ' L5', ' L3'], getline(1, '$'))
%delete _
" change with toggling 'autoindent'
call setline(1, [' L1', 'L2', 'L3'])
call feedkeys(":change!\<CR> L4\<CR> L5\<CR>.\<CR>", 'xt')
call assert_equal([' L4', ' L5', 'L2', 'L3'], getline(1, '$'))
call assert_false(&autoindent)
%delete _
" change with 'autoindent' set and toggling 'autoindent'
set autoindent
call setline(1, [' L1', 'L2', 'L3'])
call feedkeys(":change!\<CR> L4\<CR> L5\<CR>.\<CR>", 'xt')
call assert_equal([' L4', ' L5', 'L2', 'L3'], getline(1, '$'))
call assert_true(&autoindent)
set autoindent&
close!
endfunc
" Test for the :confirm command dialog " Test for the :confirm command dialog
func Test_confirm_cmd() func Test_confirm_cmd()
CheckNotGui CheckNotGui

View File

@@ -18,4 +18,10 @@ func Test_fnameescape()
endtry endtry
call assert_true(status, "ExclamationMark") call assert_true(status, "ExclamationMark")
call delete(fname) call delete(fname)
call assert_equal('\-', fnameescape('-'))
call assert_equal('\+', fnameescape('+'))
call assert_equal('\>', fnameescape('>'))
endfunc endfunc
" vim: shiftwidth=2 sts=2 expandtab

View File

@@ -18,6 +18,7 @@ func Test_ga_command()
call assert_equal("\nNUL", Do_ga('')) call assert_equal("\nNUL", Do_ga(''))
call assert_equal("\n<^A> 1, Hex 01, Oct 001, Digr SH", Do_ga("\x01")) call assert_equal("\n<^A> 1, Hex 01, Oct 001, Digr SH", Do_ga("\x01"))
call assert_equal("\n<^I> 9, Hex 09, Oct 011, Digr HT", Do_ga("\t")) call assert_equal("\n<^I> 9, Hex 09, Oct 011, Digr HT", Do_ga("\t"))
call assert_equal("\n<^@> 0, Hex 00, Octal 000", Do_ga("\n"))
call assert_equal("\n<e> 101, Hex 65, Octal 145", Do_ga('e')) call assert_equal("\n<e> 101, Hex 65, Octal 145", Do_ga('e'))
@@ -30,5 +31,13 @@ func Test_ga_command()
call assert_equal("\n<e> 101, Hex 65, Octal 145 < ́> 769, Hex 0301, Octal 1401", Do_ga("e\u0301")) call assert_equal("\n<e> 101, Hex 65, Octal 145 < ́> 769, Hex 0301, Octal 1401", Do_ga("e\u0301"))
call assert_equal("\n<e> 101, Hex 65, Octal 145 < ́> 769, Hex 0301, Octal 1401 < ̱> 817, Hex 0331, Octal 1461", Do_ga("e\u0301\u0331")) call assert_equal("\n<e> 101, Hex 65, Octal 145 < ́> 769, Hex 0301, Octal 1401 < ̱> 817, Hex 0331, Octal 1461", Do_ga("e\u0301\u0331"))
call assert_equal("\n<e> 101, Hex 65, Octal 145 < ́> 769, Hex 0301, Octal 1401 < ̱> 817, Hex 0331, Octal 1461 < ̸> 824, Hex 0338, Octal 1470", Do_ga("e\u0301\u0331\u0338")) call assert_equal("\n<e> 101, Hex 65, Octal 145 < ́> 769, Hex 0301, Octal 1401 < ̱> 817, Hex 0331, Octal 1461 < ̸> 824, Hex 0338, Octal 1470", Do_ga("e\u0301\u0331\u0338"))
" When using Mac fileformat, CR instead of NL is used for line termination
enew!
set fileformat=mac
call assert_equal("\n<^J> 10, Hex 0a, Oct 012, Digr NU", Do_ga("\r"))
bwipe! bwipe!
endfunc endfunc
" vim: shiftwidth=2 sts=2 expandtab

View File

@@ -29,3 +29,11 @@ func Test_nested_global()
call assert_equal(['nothing', '++found', 'found bad', 'bad'], getline(1, 4)) call assert_equal(['nothing', '++found', 'found bad', 'bad'], getline(1, 4))
bwipe! bwipe!
endfunc endfunc
func Test_global_error()
call assert_fails('g\\a', 'E10:')
call assert_fails('g', 'E148:')
call assert_fails('g/\(/y', 'E476:')
endfunc
" vim: shiftwidth=2 sts=2 expandtab

View File

@@ -35,6 +35,11 @@ func Test_move()
call assert_fails('1,2move 1', 'E134') call assert_fails('1,2move 1', 'E134')
call assert_fails('2,3move 2', 'E134') call assert_fails('2,3move 2', 'E134')
call assert_fails("move -100", 'E16:')
call assert_fails("move +100", 'E16:')
call assert_fails('move', 'E16:')
%bwipeout! %bwipeout!
endfunc endfunc
" vim: shiftwidth=2 sts=2 expandtab

View File

@@ -629,6 +629,25 @@ func Test_visualbell()
set belloff=all set belloff=all
endfunc endfunc
" Test for the 'write' option
func Test_write()
new
call setline(1, ['L1'])
set nowrite
call assert_fails('write Xfile', 'E142:')
set write
close!
endfunc
" Test for 'buftype' option
func Test_buftype()
new
call setline(1, ['L1'])
set buftype=nowrite
call assert_fails('write', 'E382:')
close!
endfunc
" Test for setting option values using v:false and v:true " Test for setting option values using v:false and v:true
func Test_opt_boolean() func Test_opt_boolean()
set number& set number&

View File

@@ -13,6 +13,37 @@ func Test_sort_strings()
" numbers compared as strings " numbers compared as strings
call assert_equal([1, 2, 3], sort([3, 2, 1])) call assert_equal([1, 2, 3], sort([3, 2, 1]))
call assert_equal([13, 28, 3], sort([3, 28, 13])) call assert_equal([13, 28, 3], sort([3, 28, 13]))
call assert_equal(['A', 'O', 'P', 'a', 'o', 'p', 'Ä', 'Ô', 'ä', 'ô', 'Œ', 'œ'],
\ sort(['A', 'O', 'P', 'a', 'o', 'p', 'Ä', 'Ô', 'ä', 'ô', 'œ', 'Œ']))
call assert_equal(['A', 'a', 'o', 'O', 'p', 'P', 'Ä', 'Ô', 'ä', 'ô', 'Œ', 'œ'],
\ sort(['A', 'a', 'o', 'O', 'œ', 'Œ', 'p', 'P', 'Ä', 'ä', 'ô', 'Ô'], 'i'))
" This does not appear to work correctly on Mac.
if !has('mac')
if v:collate =~? '^\(en\|fr\)_ca.utf-\?8$'
" with Canadian English capitals come before lower case.
" 'Œ' is omitted because it can sort before or after 'œ'
call assert_equal(['A', 'a', 'Ä', 'ä', 'O', 'o', 'Ô', 'ô', 'œ', 'P', 'p'],
\ sort(['A', 'a', 'o', 'O', 'œ', 'p', 'P', 'Ä', 'ä', 'ô', 'Ô'], 'l'))
elseif v:collate =~? '^\(en\|es\|de\|fr\|it\|nl\).*\.utf-\?8$'
" With the following locales, the accentuated letters are ordered
" similarly to the non-accentuated letters...
call assert_equal(['a', 'A', 'ä', 'Ä', 'o', 'O', 'ô', 'Ô', 'œ', 'Œ', 'p', 'P'],
\ sort(['A', 'a', 'o', 'O', 'œ', 'Œ', 'p', 'P', 'Ä', 'ä', 'ô', 'Ô'], 'l'))
elseif v:collate =~? '^sv.*utf-\?8$'
" ... whereas with a Swedish locale, the accentuated letters are ordered
" after Z.
call assert_equal(['a', 'A', 'o', 'O', 'p', 'P', 'ä', 'Ä', 'œ', 'œ', 'ô', 'Ô'],
\ sort(['A', 'a', 'o', 'O', 'œ', 'œ', 'p', 'P', 'Ä', 'ä', 'ô', 'Ô'], 'l'))
endif
endif
endfunc
func Test_sort_null_string()
" null strings are sorted as empty strings.
call assert_equal(['', 'a', 'b'], sort(['b', v:_null_string, 'a']))
endfunc endfunc
func Test_sort_numeric() func Test_sort_numeric()
@@ -1150,7 +1181,7 @@ func Test_sort_cmd()
\ 'input' : [ \ 'input' : [
\ '1.234', \ '1.234',
\ '0.88', \ '0.88',
\ '123.456', \ ' + 123.456',
\ '1.15e-6', \ '1.15e-6',
\ '-1.1e3', \ '-1.1e3',
\ '-1.01e3', \ '-1.01e3',
@@ -1165,7 +1196,7 @@ func Test_sort_cmd()
\ '1.15e-6', \ '1.15e-6',
\ '0.88', \ '0.88',
\ '1.234', \ '1.234',
\ '123.456' \ ' + 123.456'
\ ] \ ]
\ }, \ },
\ { \ {
@@ -1197,7 +1228,132 @@ func Test_sort_cmd()
\ 'cc', \ 'cc',
\ ] \ ]
\ }, \ },
\ {
\ 'name' : 'sort one line buffer',
\ 'cmd' : 'sort',
\ 'input' : [
\ 'single line'
\ ],
\ 'expected' : [
\ 'single line'
\ ] \ ]
\ },
\ {
\ 'name' : 'sort ignoring case',
\ 'cmd' : '%sort i',
\ 'input' : [
\ 'BB',
\ 'Cc',
\ 'aa'
\ ],
\ 'expected' : [
\ 'aa',
\ 'BB',
\ 'Cc'
\ ]
\ },
\ ]
" This does not appear to work correctly on Mac.
if !has('mac')
if v:collate =~? '^\(en\|fr\)_ca.utf-\?8$'
" en_CA.utf-8 sorts capitals before lower case
" 'Œ' is omitted because it can sort before or after 'œ'
let tests += [
\ {
\ 'name' : 'sort with locale ' .. v:collate,
\ 'cmd' : '%sort l',
\ 'input' : [
\ 'A',
\ 'E',
\ 'O',
\ 'À',
\ 'È',
\ 'É',
\ 'Ô',
\ 'Z',
\ 'a',
\ 'e',
\ 'o',
\ 'à',
\ 'è',
\ 'é',
\ 'ô',
\ 'œ',
\ 'z'
\ ],
\ 'expected' : [
\ 'A',
\ 'a',
\ 'À',
\ 'à',
\ 'E',
\ 'e',
\ 'É',
\ 'é',
\ 'È',
\ 'è',
\ 'O',
\ 'o',
\ 'Ô',
\ 'ô',
\ 'œ',
\ 'Z',
\ 'z'
\ ]
\ },
\ ]
elseif v:collate =~? '^\(en\|es\|de\|fr\|it\|nl\).*\.utf-\?8$'
" With these locales, the accentuated letters are ordered
" similarly to the non-accentuated letters.
let tests += [
\ {
\ 'name' : 'sort with locale ' .. v:collate,
\ 'cmd' : '%sort l',
\ 'input' : [
\ 'A',
\ 'E',
\ 'O',
\ 'À',
\ 'È',
\ 'É',
\ 'Ô',
\ 'Œ',
\ 'Z',
\ 'a',
\ 'e',
\ 'o',
\ 'à',
\ 'è',
\ 'é',
\ 'ô',
\ 'œ',
\ 'z'
\ ],
\ 'expected' : [
\ 'a',
\ 'A',
\ 'à',
\ 'À',
\ 'e',
\ 'E',
\ 'é',
\ 'É',
\ 'è',
\ 'È',
\ 'o',
\ 'O',
\ 'ô',
\ 'Ô',
\ 'œ',
\ 'Œ',
\ 'z',
\ 'Z'
\ ]
\ },
\ ]
endif
endif
for t in tests for t in tests
enew! enew!
@@ -1217,7 +1373,11 @@ func Test_sort_cmd()
endif endif
endfor endfor
call assert_fails('sort no', 'E474') " Needs atleast two lines for this test
call setline(1, ['line1', 'line2'])
call assert_fails('sort no', 'E474:')
call assert_fails('sort c', 'E475:')
call assert_fails('sort #pat%', 'E682:')
enew! enew!
endfunc endfunc
@@ -1319,4 +1479,46 @@ func Test_sort_cmd_report()
" the output comes from the :g command, not from the :sort " the output comes from the :g command, not from the :sort
call assert_match("6 fewer lines", res) call assert_match("6 fewer lines", res)
enew! enew!
endfunc endfunc
" Test for a :sort command followed by another command
func Test_sort_followed_by_cmd()
new
let var = ''
call setline(1, ['cc', 'aa', 'bb'])
%sort | let var = "sortcmdtest"
call assert_equal(var, "sortcmdtest")
call assert_equal(['aa', 'bb', 'cc'], getline(1, '$'))
" Test for :sort followed by a comment
call setline(1, ['3b', '1c', '2a'])
%sort /\d\+/ " sort alphabetically
call assert_equal(['2a', '3b', '1c'], getline(1, '$'))
close!
endfunc
" Test for :sort using last search pattern
func Test_sort_last_search_pat()
new
let @/ = '\d\+'
call setline(1, ['3b', '1c', '2a'])
sort //
call assert_equal(['2a', '3b', '1c'], getline(1, '$'))
close!
endfunc
" Test for retaining marks across a :sort
func Test_sort_with_marks()
new
call setline(1, ['cc', 'aa', 'bb'])
call setpos("'c", [0, 1, 0, 0])
call setpos("'a", [0, 2, 0, 0])
call setpos("'b", [0, 3, 0, 0])
%sort
call assert_equal(['aa', 'bb', 'cc'], getline(1, '$'))
call assert_equal(2, line("'a"))
call assert_equal(3, line("'b"))
call assert_equal(1, line("'c"))
close!
endfunc
" vim: shiftwidth=2 sts=2 expandtab

View File

@@ -426,6 +426,8 @@ func Test_substitute_errors()
call assert_fails('s/FOO/bar/', 'E486:') call assert_fails('s/FOO/bar/', 'E486:')
call assert_fails('s/foo/bar/@', 'E488:') call assert_fails('s/foo/bar/@', 'E488:')
call assert_fails('s/\(/bar/', 'E476:') call assert_fails('s/\(/bar/', 'E476:')
call assert_fails('s afooabara', 'E146:')
call assert_fails('s\\a', 'E10:')
setl nomodifiable setl nomodifiable
call assert_fails('s/foo/bar/', 'E21:') call assert_fails('s/foo/bar/', 'E21:')

View File

@@ -164,6 +164,69 @@ func Test_writefile_autowrite_nowrite()
set noautowrite set noautowrite
endfunc endfunc
" Test for ':w !<cmd>' to pipe lines from the current buffer to an external
" command.
func Test_write_pipe_to_cmd()
if !has('unix')
return
endif
new
call setline(1, ['L1', 'L2', 'L3', 'L4'])
2,3w !cat > Xfile
call assert_equal(['L2', 'L3'], readfile('Xfile'))
close!
call delete('Xfile')
endfunc
" Test for :saveas
func Test_saveas()
call assert_fails('saveas', 'E471:')
call writefile(['L1'], 'Xfile')
new Xfile
new
call setline(1, ['L1'])
call assert_fails('saveas Xfile', 'E139:')
close!
enew | only
call delete('Xfile')
endfunc
func Test_write_errors()
" Test for writing partial buffer
call writefile(['L1', 'L2', 'L3'], 'Xfile')
new Xfile
call assert_fails('1,2write', 'E140:')
close!
" Try to overwrite a directory
if has('unix')
call mkdir('Xdir1')
call assert_fails('write Xdir1', 'E17:')
call delete('Xdir1', 'd')
endif
" Test for :wall for a buffer with no name
enew | only
call setline(1, ['L1'])
call assert_fails('wall', 'E141:')
enew!
" Test for writing a 'readonly' file
new Xfile
set readonly
call assert_fails('write', 'E45:')
close
" Test for writing to a read-only file
new Xfile
call setfperm('Xfile', 'r--r--r--')
call assert_fails('write', 'E505:')
call setfperm('Xfile', 'rw-rw-rw-')
close
call delete('Xfile')
endfunc
func Test_writefile_sync_dev_stdout() func Test_writefile_sync_dev_stdout()
if !has('unix') if !has('unix')
return return

View File

@@ -268,6 +268,8 @@ describe('packadd', function()
call assert_match('look-here', tags1[0]) call assert_match('look-here', tags1[0])
let tags2 = readfile(docdir2 . '/tags') let tags2 = readfile(docdir2 . '/tags')
call assert_match('look-away', tags2[0]) call assert_match('look-away', tags2[0])
call assert_fails('helptags abcxyz', 'E150:')
endfunc endfunc
func Test_colorscheme() func Test_colorscheme()