Merge #4303 'vim-patch:7.4.{951,1143,1144}'.

This commit is contained in:
Justin M. Keyes
2016-04-25 03:56:33 -04:00
9 changed files with 209 additions and 55 deletions

View File

@@ -1646,7 +1646,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][!] [i][u][r][n][x][o][b] [/{pattern}/] :[range]sor[t][!] [b][f][i][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.
@@ -1654,10 +1654,18 @@ found here: |sort()|, |uniq()|.
With [i] case is ignored. With [i] case is ignored.
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
in the line (after or inside a {pattern} match). in the line (after or inside a {pattern} match).
One leading '-' is included in the number. One leading '-' is included in the number.
With [f] sorting is done on the Float in the line.
The value of Float is determined similar to passing
the text (after or inside a {pattern} match) to
str2float() function. This option is available only
if Vim was compiled with Floating point support.
With [x] sorting is done on the first hexadecimal With [x] sorting is done on the first hexadecimal
number in the line (after or inside a {pattern} number in the line (after or inside a {pattern}
match). A leading "0x" or "0X" is ignored. match). A leading "0x" or "0X" is ignored.
@@ -1669,10 +1677,10 @@ found here: |sort()|, |uniq()|.
With [b] sorting is done on the first binary number in With [b] sorting is done on the first binary number in
the line (after or inside a {pattern} match). the line (after or inside a {pattern} match).
With [u] only keep the first of a sequence of With [u] (u stands for unique) only keep the first of
identical lines (ignoring case when [i] is used). a sequence of identical lines (ignoring case when [i]
Without this flag, a sequence of identical lines is used). Without this flag, a sequence of identical
will be kept in their original order. lines will be kept in their original order.
Note that leading and trailing white space may cause Note that leading and trailing white space may cause
lines to be different. lines to be different.

View File

@@ -6144,6 +6144,10 @@ sort({list} [, {func} [, {dict}]]) *sort()* *E702*
strtod() function to parse numbers, Strings, Lists, Dicts and strtod() function to parse numbers, Strings, Lists, Dicts and
Funcrefs will be considered as being 0). Funcrefs will be considered as being 0).
When {func} is given and it is 'N' then all items will be
sorted numerical. This is like 'n' but a string containing
digits will be used as the number they represent.
When {func} is a |Funcref| or a function name, this function When {func} is a |Funcref| or a function name, this function
is called to compare items. The function is invoked with two is called to compare items. The function is invoked with two
items as argument and must return zero if they are equal, 1 or items as argument and must return zero if they are equal, 1 or
@@ -6158,6 +6162,11 @@ sort({list} [, {func} [, {dict}]]) *sort()* *E702*
on numbers, text strings will sort next to each other, in the on numbers, text strings will sort next to each other, in the
same order as they were originally. same order as they were originally.
The sort is stable, items which compare equal (as number or as
string) will keep their relative position. E.g., when sorting
on numbers, text strings will sort next to each other, in the
same order as they were originally.
Also see |uniq()|. Also see |uniq()|.
Example: > Example: >

View File

@@ -14947,6 +14947,8 @@ typedef struct {
static int item_compare_ic; static int item_compare_ic;
static bool item_compare_numeric; static bool item_compare_numeric;
static bool item_compare_numbers;
static bool item_compare_float;
static char_u *item_compare_func; static char_u *item_compare_func;
static dict_T *item_compare_selfdict; static dict_T *item_compare_selfdict;
static int item_compare_func_err; static int item_compare_func_err;
@@ -14968,6 +14970,21 @@ static int item_compare(const void *s1, const void *s2, bool keep_zero)
si2 = (sortItem_T *)s2; si2 = (sortItem_T *)s2;
typval_T *tv1 = &si1->item->li_tv; typval_T *tv1 = &si1->item->li_tv;
typval_T *tv2 = &si2->item->li_tv; typval_T *tv2 = &si2->item->li_tv;
if (item_compare_numbers) {
long v1 = get_tv_number(tv1);
long v2 = get_tv_number(tv2);
return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
}
if (item_compare_float) {
float_T v1 = get_tv_float(tv1);
float_T v2 = get_tv_float(tv2);
return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
}
// encode_tv2string() puts quotes around a string and allocates memory. Don't // encode_tv2string() puts quotes around a string and allocates memory. Don't
// do that for string variables. Use a single quote when comparing with // do that for string variables. Use a single quote when comparing with
// a non-string to do what the docs promise. // a non-string to do what the docs promise.
@@ -15114,6 +15131,8 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort)
item_compare_ic = FALSE; item_compare_ic = FALSE;
item_compare_numeric = false; item_compare_numeric = false;
item_compare_numbers = false;
item_compare_float = false;
item_compare_func = NULL; item_compare_func = NULL;
item_compare_selfdict = NULL; item_compare_selfdict = NULL;
@@ -15135,6 +15154,12 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort)
if (STRCMP(item_compare_func, "n") == 0) { if (STRCMP(item_compare_func, "n") == 0) {
item_compare_func = NULL; item_compare_func = NULL;
item_compare_numeric = true; item_compare_numeric = true;
} else if (STRCMP(item_compare_func, "N") == 0) {
item_compare_func = NULL;
item_compare_numbers = true;
} else if (STRCMP(item_compare_func, "f") == 0) {
item_compare_func = NULL;
item_compare_float = true;
} else if (STRCMP(item_compare_func, "i") == 0) { } else if (STRCMP(item_compare_func, "i") == 0) {
item_compare_func = NULL; item_compare_func = NULL;
item_compare_ic = TRUE; item_compare_ic = TRUE;
@@ -17836,6 +17861,33 @@ long get_tv_number_chk(typval_T *varp, int *denote)
return n; return n;
} }
static float_T get_tv_float(typval_T *varp)
{
switch (varp->v_type) {
case VAR_NUMBER:
return (float_T)(varp->vval.v_number);
case VAR_FLOAT:
return varp->vval.v_float;
break;
case VAR_FUNC:
EMSG(_("E891: Using a Funcref as a Float"));
break;
case VAR_STRING:
EMSG(_("E892: Using a String as a Float"));
break;
case VAR_LIST:
EMSG(_("E893: Using a List as a Float"));
break;
case VAR_DICT:
EMSG(_("E894: Using a Dictionary as a Float"));
break;
default:
EMSG2(_(e_intern2), "get_tv_float()");
break;
}
return 0;
}
/* /*
* Get the lnum from the first argument. * Get the lnum from the first argument.
* Also accepts ".", "$", etc., but that only works for the current buffer. * Also accepts ".", "$", etc., but that only works for the current buffer.

View File

@@ -3,6 +3,7 @@
*/ */
#include <assert.h> #include <assert.h>
#include <float.h>
#include <stdbool.h> #include <stdbool.h>
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
@@ -273,17 +274,26 @@ 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_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
static int sort_flt; ///< sort on floating number
static int sort_abort; /* flag to indicate if sorting has been interrupted */ static int sort_abort; ///< flag to indicate if sorting has been interrupted
/* Struct to store info to be sorted. */ /// Struct to store info to be sorted.
typedef struct { typedef struct {
linenr_T lnum; /* line number */ linenr_T lnum; ///< line number
long start_col_nr; /* starting column number or number */ long start_col_nr; ///< starting column number or number
long end_col_nr; /* ending column number */ long end_col_nr; ///< ending column number
union {
struct {
long start_col_nr; ///< starting column number
long end_col_nr; ///< ending column number
} line;
long value; ///< value if sorting by integer
float_T value_flt; ///< value if sorting by float
} st_u;
} sorti_T; } sorti_T;
@@ -302,21 +312,26 @@ static int sort_compare(const void *s1, const void *s2)
if (got_int) if (got_int)
sort_abort = TRUE; sort_abort = TRUE;
/* When sorting numbers "start_col_nr" is the number, not the column // When sorting numbers "start_col_nr" is the number, not the column
* number. */ // number.
if (sort_nr) if (sort_nr) {
result = l1.start_col_nr == l2.start_col_nr ? 0 result = l1.st_u.value == l2.st_u.value
: l1.start_col_nr > l2.start_col_nr ? 1 : -1; ? 0 : l1.st_u.value > l2.st_u.value
else { ? 1 : -1;
/* We need to copy one line into "sortbuf1", because there is no } else if (sort_flt) {
* guarantee that the first pointer becomes invalid when obtaining the result = l1.st_u.value_flt == l2.st_u.value_flt
* second one. */ ? 0 : l1.st_u.value_flt > l2.st_u.value_flt
STRNCPY(sortbuf1, ml_get(l1.lnum) + l1.start_col_nr, ? 1 : -1;
l1.end_col_nr - l1.start_col_nr + 1); } else {
sortbuf1[l1.end_col_nr - l1.start_col_nr] = 0; // We need to copy one line into "sortbuf1", because there is no
STRNCPY(sortbuf2, ml_get(l2.lnum) + l2.start_col_nr, // guarantee that the first pointer becomes invalid when obtaining the
l2.end_col_nr - l2.start_col_nr + 1); // second one.
sortbuf2[l2.end_col_nr - l2.start_col_nr] = 0; STRNCPY(sortbuf1, ml_get(l1.lnum) + l1.st_u.line.start_col_nr,
l1.st_u.line.end_col_nr - l1.st_u.line.start_col_nr + 1);
sortbuf1[l1.st_u.line.end_col_nr - l1.st_u.line.start_col_nr] = 0;
STRNCPY(sortbuf2, ml_get(l2.lnum) + l2.st_u.line.start_col_nr,
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] = 0;
result = sort_ic ? STRICMP(sortbuf1, sortbuf2) result = sort_ic ? STRICMP(sortbuf1, sortbuf2)
: STRCMP(sortbuf1, sortbuf2); : STRCMP(sortbuf1, sortbuf2);
@@ -360,7 +375,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 = 0; sort_abort = sort_ic = sort_rx = sort_nr = sort_flt = 0;
size_t format_found = 0; size_t format_found = 0;
for (p = eap->arg; *p != NUL; ++p) { for (p = eap->arg; *p != NUL; ++p) {
@@ -370,7 +385,10 @@ void ex_sort(exarg_T *eap)
} else if (*p == 'r') { } else if (*p == 'r') {
sort_rx = true; sort_rx = true;
} else if (*p == 'n') { } else if (*p == 'n') {
sort_nr = 2; sort_nr = 1;
format_found++;
} else if (*p == 'f') {
sort_flt = 1;
format_found++; format_found++;
} else if (*p == 'b') { } else if (*p == 'b') {
sort_what = STR2NR_BIN + STR2NR_FORCE; sort_what = STR2NR_BIN + STR2NR_FORCE;
@@ -423,7 +441,8 @@ void ex_sort(exarg_T *eap)
goto sortend; goto sortend;
} }
// From here on "sort_nr" is used as a flag for any number sorting. // From here on "sort_nr" is used as a flag for any integer number
// sorting.
sort_nr += sort_what; sort_nr += sort_what;
// Make an array with all line numbers. This avoids having to copy all // Make an array with all line numbers. This avoids having to copy all
@@ -452,7 +471,7 @@ void ex_sort(exarg_T *eap)
end_col = 0; end_col = 0;
} }
if (sort_nr) { if (sort_nr || sort_flt) {
// Make sure vim_str2nr doesn't read any digits past the end // Make sure vim_str2nr doesn't read any digits past the end
// of the match, by temporarily terminating the string there // of the match, by temporarily terminating the string there
s2 = s + end_col; s2 = s + end_col;
@@ -460,29 +479,42 @@ void ex_sort(exarg_T *eap)
*s2 = NUL; *s2 = NUL;
// Sorting on number: Store the number itself. // Sorting on number: Store the number itself.
p = s + start_col; p = s + start_col;
if (sort_what & STR2NR_HEX) { if (sort_nr) {
s = skiptohex(p); if (sort_what & STR2NR_HEX) {
} else if (sort_what & STR2NR_BIN) { s = skiptohex(p);
s = (char_u*) skiptobin((char*) p); } else if (sort_what & STR2NR_BIN) {
s = (char_u *)skiptobin((char *)p);
} else {
s = skiptodigit(p);
}
if (s > p && s[-1] == '-') {
s--; // include preceding negative sign
}
if (*s == NUL) {
// empty line should sort before any number
nrs[lnum - eap->line1].st_u.value = -MAXLNUM;
} else {
vim_str2nr(s, NULL, NULL, sort_what,
&nrs[lnum - eap->line1].st_u.value, NULL, 0);
}
} else { } else {
s = skiptodigit(p); s = skipwhite(p);
} if (*s == '+') {
if (s > p && s[-1] == '-') { s = skipwhite(s + 1);
// include preceding negative sign }
s--;
} if (*s == NUL) {
if (*s == NUL) { // empty line should sort before any number
// empty line should sort before any number nrs[lnum - eap->line1].st_u.value_flt = -DBL_MAX;
nrs[lnum - eap->line1].start_col_nr = -MAXLNUM; } else {
} else { nrs[lnum - eap->line1].st_u.value_flt = strtod((char *)s, NULL);
vim_str2nr(s, NULL, NULL, sort_what, }
&nrs[lnum - eap->line1].start_col_nr, NULL, 0);
} }
*s2 = c; *s2 = c;
} else { } else {
// Store the column to sort at. // Store the column to sort at.
nrs[lnum - eap->line1].start_col_nr = start_col; nrs[lnum - eap->line1].st_u.line.start_col_nr = start_col;
nrs[lnum - eap->line1].end_col_nr = end_col; nrs[lnum - eap->line1].st_u.line.end_col_nr = end_col;
} }
nrs[lnum - eap->line1].lnum = lnum; nrs[lnum - eap->line1].lnum = lnum;

View File

@@ -36,9 +36,12 @@ SCRIPTS := \
test_breakindent.out \ test_breakindent.out \
test_close_count.out \ test_close_count.out \
test_marks.out \ test_marks.out \
test_match_conceal.out \
NEW_TESTS = test_viml.res # Tests using runtest.vim.vim.
# Keep test_alot*.res as the last one, sort the others.
NEW_TESTS = \
test_viml.res \
test_alot.res
SCRIPTS_GUI := test16.out SCRIPTS_GUI := test16.out

View File

@@ -0,0 +1,3 @@
" A series of tests that can run in one Vim invocation.
" This makes testing go faster, since Vim doesn't need to restart.

View File

@@ -533,8 +533,8 @@ static int included_patches[] = {
// 1147, // 1147,
// 1146 NA // 1146 NA
// 1145 NA // 1145 NA
// 1144 NA 1144,
// 1143, 1143,
// 1142, // 1142,
1141, 1141,
// 1140, // 1140,
@@ -726,7 +726,7 @@ static int included_patches[] = {
// 954 NA // 954 NA
953, 953,
952, 952,
// 951, 951,
950, 950,
949, 949,
// 948 NA // 948 NA

View File

@@ -668,4 +668,22 @@ describe(':sort', function()
b0b101100 b0b101100
b0b111000]]) b0b111000]])
end) end)
it('float', function()
insert([[
1.234
0.88
123.456
1.15e-6
-1.1e3
-1.01e3]])
execute([[sort f]])
expect([[
-1.1e3
-1.01e3
1.15e-6
0.88
1.234
123.456]])
end)
end) end)

View File

@@ -0,0 +1,29 @@
local helpers = require('test.functional.helpers')
local clear = helpers.clear
local eq = helpers.eq
local eval = helpers.eval
describe('sort', function()
before_each(clear)
it('numbers compared as strings', function()
eq({1, 2, 3}, eval('sort([3, 2, 1])'))
eq({13, 28, 3}, eval('sort([3, 28, 13])'))
end)
it('numbers compared as numeric', function()
eq({1, 2, 3}, eval("sort([3, 2, 1], 'n')"))
eq({3, 13, 28}, eval("sort([3, 28, 13], 'n')"))
-- Strings are not sorted.
eq({'13', '28', '3'}, eval("sort(['13', '28', '3'], 'n')"))
end)
it('numbers compared as numbers', function()
eq({3, 13, 28}, eval("sort([13, 28, 3], 'N')"))
eq({'3', '13', '28'}, eval("sort(['13', '28', '3'], 'N')"))
end)
it('numbers compared as float', function()
eq({0.28, 3, 13.5}, eval("sort([13.5, 0.28, 3], 'f')"))
end)
end)